2016-01-26 139 views
1

我不確定是否可以這樣做,但我有一個執行阻止操作的異步工作流。我想取消它,如果它已經運行很長一段時間,包括當前正在執行工作流程的線程。取消執行阻止同步工作的異步工作流

這裏是我的測試用例:

let counter = ref 0 
let work = async { 
    let computation = async { 
     System.Threading.Interlocked.Increment(counter) |> ignore 
     let blockingWork = Async.Sleep(2000) |> Async.RunSynchronously 
     System.Threading.Interlocked.Increment(counter) |> ignore 
    } 
    do! computation 
} 

use cts = new System.Threading.CancellationTokenSource(1000) 
let tryCancelled = Async.TryCancelled(work, fun _ -> printf "Cancelled") 
do Async.Start(tryCancelled, cts.Token) 
System.Threading.Thread.Sleep(3000) //Simulate other work 
counter.contents |> should equal 1 

的事情是,工作流成功取消,補償函數被調用,但計算仍在繼續,增加計數器...

+2

異步中的取消支持基本上可以工作,如果你用'do!','let!'和一些類似'while'的結構調用其他asyncs - 它不會中斷同步。來電!所以你必須將令牌傳遞給同步。阻止並檢查它是否被取消,或者你必須使用Threads和Abort來做一些健身活動(**不推薦**!) - 順便說一句:這裏假定睡眠僅用於示範 - 如果沒有,你會得到答案;) – Carsten

+0

另外:你沒有取消你的例子中的令牌 - 這當然也會導致你的假設無效;) – Carsten

+0

@Carsten好吧,我想我明白了...我的恐懼是我需要中斷線程,因爲同步 - 我需要執行的工作可能需要很多時間,並且需要調用外部庫,我無法控制... –

回答

1

執行blockingWork在異步的情況下做! blocking工作

let counter = ref 0 
let work = async { 
    let computation = async { 
     System.Threading.Interlocked.Increment(counter) |> ignore 
     let blockingWork = Async.Sleep(2000) 
     do! blockingWork 
     System.Threading.Interlocked.Increment(counter) |> ignore 
    } 
    do! computation 
} 

let doit() = 
    use cts = new System.Threading.CancellationTokenSource(1000) 
    let tryCancelled = Async.TryCancelled(work, fun _ -> printf "Cancelled") 
    do Async.Start(tryCancelled, cts.Token) 
    System.Threading.Thread.Sleep(3000) //Simulate other work 
    counter.contents // |> should equal 1 

doit() 
+1

我的猜測:'Async.Sleep'用於演示.... – Carsten

+0

是的,Async.Sleep用於演示。您可以將其更改爲Thread.Sleep(),並將管道跳到Async.RunSynchronously –