2017-03-08 50 views
2

有沒有一種方法可以使用來自async包的async線程中的cancel?我可以看到你可以從線程外部取消它,但是我想知道是否有可以停止它自己的執行的cancelSelf :: IO()函數。我可能 staple東西一起獨特的id代和線程引用,線程本身可以引用,但似乎太多共享Map。我可以逃避一個未捕獲的異常或什麼?取消線程本身內的異步線程

+0

在我看來,既然你提出的'cancelSelf'功能需要你在IO在點上,你會想要取消,取而代之的是'EitherT String IO'同樣容易,而通過返回'Left「取消」'或者其他任何東西只是「取消」。 – amalloy

回答

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 
+0

「'mfix f'只執行一次動作'f',最終輸出作爲輸入反饋。因此'f'不應該是嚴格的,因爲'mfix f'會發散。是的,以一種非常糟糕的方式 - 它會阻止「takeMVar」。 – Alec