Haskell Async如何在中断后可靠地运行清理操作?

时间:2017-03-28 19:00:53

标签: haskell asynchronous concurrency

为了便于讨论,这是一个简短的例子。它产生Async,其中有26个并发子Async

import Control.Concurrent (threadDelay)
import Control.Concurrent.Async (async, cancel, forConcurrently_)
import Control.Exception (finally)
import Data.Char (toUpper)
import Prelude ((*), (*>), ($))
import System.IO (IO, hPutStr, stderr)

main :: IO ()
main = do
    a <- async $ forConcurrently_ ['a'..'z'] $ \c ->
        (print c *> delay 2) `finally` print (toUpper c)
    delay 1
    cancel a
  where
    delay sec = threadDelay (sec * 1000000)
    print c = hPutStr stderr [c]

每个孩子

  1. 打印一封信(表示该流程已经开始)
  2. 暂停
  3. 使用finally时,应始终打印该字母的大写版本(代表“清理”操作)。
  4. 然后,我们暂停足够长的时间让所有Async启动,但不足以让它们完成,然后在父项上调用cancel,从而为每个Async抛出一个异常finally s。

    我希望每个abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 操作都能运行,从而产生输出

    abcdefghijklmnopqrstuvwxyzABC
    

    但我得到了

    a

    我如何推断这个例子中发生的事情,以及获得我正在寻找的那种可靠清理行为的正确方法是什么?

1 个答案:

答案 0 :(得分:2)

您使用的是什么版本的asynccancel2.1.1的行为已更改为等待线程实际退出。在早期版本中,它只抛出异步异常并退出。在您的情况下,所有线程都收到异常,但并非所有线程都有机会处理它(打印上面的char),因为main已经退出。尝试添加例如delay 10之后的cancel。如果您使用2.1.1,那么它可能(或可能不)表示async中的错误。

增加:它确实看起来像一个错误:https://github.com/simonmar/async/issues/59#issuecomment-289894612