2014-12-01 43 views
15

當前正在使用下面的代碼來等待一系列任務完成。但是,我現在有一種情況,我希望能夠取消/中止WhenAll呼叫,最好通過取消令牌。我會怎麼做呢?我該如何取消Task.WhenAll?

Dim TaskCollection As New List(Of Tasks.Task) 
    For x As Integer = 1 To Threads 
    Dim NewTask As Tasks.Task = TaskHandler.Delegates(DelegateKey).Invoke(Me, Proxies, TotalParams).ContinueWith(Sub() ThreadFinished()) 
    TaskCollection.Add(NewTask) 
    Next 

    Await Tasks.Task.WhenAll(TaskCollection) 

我假設它會沿着下一代代碼行,但我不確定'XXX'會發生什麼。

Await Tasks.Task.WhenAny(Tasks.Task.WhenAll(TaskCollection), XXX) 
+3

通常情況下,您想要自行取消實際任務。你確定你只想取消*等待這些任務嗎? – 2014-12-01 22:14:32

+0

這是一個有趣的問題。如果他沒有得到大部分答案,我就不會解決它。 – 2014-12-01 22:23:53

+0

@StephenCleary我有一個問題,其中一個任務沒有完成。目前,我不知道爲什麼。當我決定時,我需要一個故障安全來取消WaitAll。我知道它不能解決卡住的任務,但需要快速修復。我想解決主要問題,但我有一個龐大的代碼庫,我不確定它在哪裏。由於大小,我無法在此發佈完整的代碼,也無法透露我的客戶已付費的代碼。 – iguanaman 2014-12-01 22:27:27

回答

17

使用TaskCompletionSource<T>爲某些尚未具有異步API的異步條件創建任務。使用CancellationToken.Register將基於CancellationToken的現代取消系統掛接到另一個取消系統。你的解決方案只需要將這兩者結合起來。

我有一個CancellationToken.AsTask() extension method in my AsyncEx library,但你可以編寫自己的這樣:

<System.Runtime.CompilerServices.Extension> _ 
Public Shared Function AsTask(cancellationToken As CancellationToken) As Task 
    Dim tcs = New TaskCompletionSource(Of Object)() 
    cancellationToken.Register(Function() tcs.TrySetCanceled(), useSynchronizationContext := False) 
    Return tcs.Task 
End Function 

用法如你預期:

Await Task.WhenAny(Task.WhenAll(taskCollection), cancellationToken.AsTask()) 
+7

'cancellationToken.AsTask()':'Task.Delay(Timeout.Infinite,token)'的替代方案。 – Noseratio 2014-12-02 04:20:13

+0

將其標記爲答案,因爲它允許我使用鏈接的CancellationToken。 – iguanaman 2014-12-02 14:49:16

+0

不錯的升級。我可以在幾個地方看到使用AsTask。 – 2014-12-11 04:32:00

3
Dim tcs as new TaskCompletionSource(Of Object)() 
Await Tasks.Task.WhenAny(Tasks.Task.WhenAll(TaskCollection), tcs) 

要取消,請撥打tcs.SetResult(沒有)。這會激發你的Task.WhenAny。

0

您也可以等待延遲:

await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(1000));