Я создал эту небольшую программу, которая создает долговременный thunk, который в конечном итоге терпит неудачу с исключением. Затем несколько потоков пытаются оценить его.
import Control.Monad
import Control.Concurrent
import Control.Concurrent.MVar
main = do
let thunk = let p = product [1..10^4]
in if p `mod` 2 == 0 then error "exception"
else ()
children <- replicateM 2000 (myForkIO (print thunk))
mapM_ takeMVar children
-- | Spawn a thread and return a MVar which can be used to wait for it.
myForkIO :: IO () -> IO (MVar ())
myForkIO io = do
mvar <- newEmptyMVar
forkFinally io (\_ -> putMVar mvar ())
return mvar
Увеличение количества потоков явно не влияет на вычисление, что говорит о том, что неудавшийся thunk сохраняет исключение в качестве результата. Это правда? Является ли это поведение документированным/указано где-то?
Обновление: Изменение строки forkFinally
на
forkFinally io (\e -> print e >> putMVar mvar ())
подтверждает, что каждый поток выходит из строя с исключением.