2014-12-01 37 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));