Как я могу отменить Task.WhenAll?

Currenly, используя следующий код, чтобы дождаться завершения набора задач. Однако теперь у меня есть ситуация, когда я хочу иметь возможность отменить/прервать вызов 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)

Ответы

Ответ 1

Используйте TaskCompletionSource<T> для создания задачи для некоторого асинхронного условия, которое еще не имеет асинхронного API. Используйте CancellationToken.Register, чтобы перехватить современную систему отмены на основе CancellationToken в другую систему отмены. Ваше решение просто должно объединить эти два.

У меня есть метод расширения CancellationToken.AsTask() в моей библиотеке AsyncEx, но вы можете написать свое собственное как таковое:

<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())

Ответ 2

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

Чтобы отменить, вызовите tcs.SetResult(Nothing). Это запустит вашу Task.WhenAny.

Ответ 3

Вы также можете ожидать задержки:

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