有没有办法在async包中使用async
调用的线程中使用cancelSelf :: IO ()
?我可以看到你可以从线程外部取消它,但我想知道是否有一个Map
函数可以停止自己的执行。我可以使用唯一的id生成和共享Async
<div class="row">
<div class="col-xs-2 col-xs-offset-5"></div>
</div>
个col
线程引用来组合一些东西,线程本身可以引用它,但这看起来太多了。我可以逃避未被捕获的异常或其他什么吗?
答案 0 :(得分:5)
异步操作可以自行取消。不过,这涉及到一些技巧。
{-# LANGUAGE RecursiveDo #-}
import Control.Concurrent.Async
main :: IO ()
main = do
rec let doCancel = cancel calculate
calculate <- async doCancel
wait calculate
从理论上讲,你可以在没有RecursiveDo
的情况下做到这一点,但是我从来没有想过手写mfix
表达式(RecursiveDo
绑定到desugar)。
RecursiveDo
允许您在do块内创建一个相互递归的定义集,即使某些定义与<-
绑定,有些定义在let
语句中定义。与往常一样,如果涉及真正的循环,计算将会发生分歧。但是在很多情况下你想要做的就是能够引用上面例子中的其他名称,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