gpt4 book ai didi

exception - 如果 thunk 导致异常,异常是否会保留为 thunk 的结果?

转载 作者:行者123 更新时间:2023-12-02 19:02:03 28 4
gpt4 key购买 nike

我创建了这个小程序,它创建了一个长时间运行的 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 ())

确认每个线程因异常而失败。

最佳答案

让我通过使用ghc-heap-view展示GHC实际上是如何做到这一点来回答这个问题的。图书馆。您可以使用 ghc-vis 重现此内容并获得漂亮的照片。

我首先创建一个在某处带有异常值的数据结构:

Prelude> :script /home/jojo/.cabal/share/ghc-heap-view-0.5.1/ghci 
Prelude> let x = map ((1::Int) `div`) [1,0]

起初它纯粹是一个thunk(似乎涉及各种类型类):

Prelude> :printHeap x
let f1 = _fun
in (_bco [] (_bco (D:Integral (D:Real (D:Num _fun _fun _fun _fun _fun _fun _fun) (D:Ord (D:Eq _fun _fun) _fun _fun _fun _fun _fun _fun _fun) _fun) (D:Enum _fun _fun f1 f1 _fun _fun _fun _fun) _fun _fun _fun _fun _fun _fun _fun) _fun) _fun)()

现在我评估非异常抛出部分:

Prelude> (head x, length x)
(1,2)
Prelude> System.Mem.performGC
Prelude> :printHeap x
[I# 1,_thunk (_fun (I# 1)) (I# 0)]

列表的第二个元素仍然只是一个“正常”的重击。现在我评估一下,得到一个异常,然后再看一遍:

Prelude> last x
*** Exception: divide by zero
Prelude> System.Mem.performGC
Prelude> :printHeap x
[I# 1,_thunk (SomeException (D:Exception _fun (D:Show _fun _fun _fun) _fun _fun) DivideByZero())]

您可以看到它现在是一个引用 SomeException 的 thunk。目的。 SomeException 数据构造函数的类型为 forall e 。 Exception e => e -> SomeException,所以构造函数的第二个参数是 DivideByZero ArithException 异常的构造函数,第一个参数对应 Exception类型类实例。

这个 thunk 可以像任何其他 Haskell 值一样传递,并且如果被评估,将再次引发异常。而且,就像任何其他值一样,可以共享异常:

Prelude> let y = (last x, last x)
Prelude> y
(*** Exception: divide by zero
Prelude> snd y
*** Exception: divide by zero
Prelude> System.Mem.performGC
Prelude> :printHeap y
let x1 = SomeException (D:Exception _fun (D:Show _fun _fun _fun) _fun _fun) DivideByZero()
in (_thunk x1,_thunk x1)

线程和 MVar 也会发生同样的情况,没有什么特别的。

关于exception - 如果 thunk 导致异常,异常是否会保留为 thunk 的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18018254/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com