从线程本身取消异步线程

Canceling an Async thread from within the thread itself

有没有办法在使用 async 包中的 async 调用的线程中使用 cancel?我可以看到你可以从线程外部取消它,但我想知道是否有一个 cancelSelf :: IO () 函数可以停止它自己的执行。我 可以 将一些东西与唯一 ID 生成和共享 MapAsync 线程引用结合在一起,线程本身可以引用,但这似乎太多了。我可以逃避未捕获的异常吗?

异步操作可以自行取消。不过,它涉及到一些技巧。

{-# LANGUAGE RecursiveDo #-}

import Control.Concurrent.Async

main :: IO ()
main = do
    rec let doCancel = cancel calculate
        calculate <- async doCancel
    wait calculate

理论上,你可以在没有 RecursiveDo 的情况下做到这一点,但我从来不想手动编写 mfix 表达式(RecursiveDo 绑定去糖)。

RecursiveDo 允许您在 do 块内创建一组相互递归的定义,即使某些定义与 <- 绑定并且某些定义在 [=17= 内也是如此] 陈述。与往常一样,如果涉及到真正的循环,计算就会出现分歧。但是在很多情况下,您想要做的就是能够像上面的示例一样引用其他名称,并且 RecursiveDo 工作得很好。

哦,the implementation of mfix for IO 太可怕了。我很高兴我不必自己写。

-- 编辑--

由于几乎没有收到任何反馈,我意识到如何使用它来解决您的问题并不完全清楚。所以这是一个扩展示例,它使用组合器生成可以取消自身的 Async

{-# LANGUAGE RecursiveDo #-}

-- obviously want the async library
import Control.Concurrent.Async

-- used in selfCancelableAsync
import Control.Monad      (forever)
import Control.Concurrent (threadDelay)

-- only used for demonstration
import System.Random      (randomIO)

main :: IO ()
main = do
    a <- selfCancelableAsync $ \selfCancel -> do
        choice <- randomIO
        if choice then return "Success!" else selfCancel
    result <- wait a
    putStrLn result

-- spawns an Async that has the ability to cancel itself by
-- using the action passed to the IO action it's running
selfCancelableAsync :: (IO a -> IO b) -> IO (Async b)
selfCancelableAsync withCancel = do
    rec let doCancel = do
                cancel calculate
                -- This must never return to ensure it has the correct type.
                -- It uses threadDelay to ensure it's not hogging resources
                -- if it takes a moment to get killed.
                forever $ threadDelay 1000

        calculate <- async $ withCancel doCancel

    return calculate