Chcę napisać funkcję, która zajmuje limit czasu (w sekundach) i listę, i oblicza jak najwięcej elementów listy, jak to możliwe w terminie.Obliczyć jak najwięcej listy w ustalonym czasie
Moja pierwsza próba była najpierw napisać następującą funkcję, która razy czystą obliczenia i zwraca czas jaki upłynął wraz z wynikiem:
import Control.DeepSeq
import System.CPUTime
type Time = Double
timed :: (NFData a) => a -> IO (a, Time)
timed x = do t1 <- getCPUTime
r <- return $!! x
t2 <- getCPUTime
let diff = fromIntegral (t2 - t1)/10^12
return (r, diff)
mogę następnie zdefiniować funkcję Chcę chodzi o to:
timeLimited :: (NFData a) => Time -> [a] -> IO [a]
timeLimited remaining [] = return []
timeLimited remaining (x:xs) = if remaining < 0
then return []
else do
(y,t) <- timed x
ys <- timeLimited (remaining - t) xs
return (y:ys)
To jednak nie jest w porządku. Nawet ignorując błędy synchronizacji i błędy zmiennoprzecinkowe, podejście to nigdy nie zatrzymuje obliczeń elementu listy po uruchomieniu, co oznacza, że może (i faktycznie normalnie) przekroczyć limit czasu.
Jeśli zamiast miałem funkcję, która mogłaby ocena zwarcie gdyby brać zbyt długo:
timeOut :: Time -> a -> IO (Maybe (a,t))
timeOut = undefined
wtedy mógłbym napisać funkcję, że naprawdę ma:
timeLimited' :: Time -> [a] -> IO [a]
timeLimited' remaining [] = return []
timeLimited' remaining (x:xs) = do
result <- timeOut remaining x
case result of
Nothing -> return []
Just (y,t) -> do
ys <- timeLimited' (remaining - t) xs
return (y:ys)
Moje pytania to:
- Jak napisać
timeOut
? - Czy istnieje lepszy sposób na zapisanie funkcji
timeLimited
, na przykład takiej, która nie cierpi z powodu nagromadzonego błędu zmiennoprzecinkowego od wielokrotnego sumowania różnic czasowych?
Nie możesz uruchomić dwóch wątków, w których jeden wątek odlicza czas i zabija wątek obliczeniowy po osiągnięciu limitu czasu? –
Może. Nie napisałem zbyt wiele współbieżnego kodu w Haskell. W jaki sposób mogłaby zwrócić częściowo ocenioną listę? –
Najprawdopodobniej umieściłbym listę w TVAR i zabrałaby każdy nowy węzeł do niej. Właśnie zobaczyłem, że STM.TVar ma funkcję o nazwie 'registerDelay', która również może być pomocna w synchronizowaniu dwóch wątków. –