因此,task.Wait()
可以转换为await task
。当然,语义是不同的,但这大致是我如何将带有Waits
的阻塞代码转换为带有awaits
的异步代码。
我的问题是如何将task.Wait(CancellationToken)
转换为相应的await
声明?
答案 0 :(得分:9)
await
用于异步方法/委托,它们接受CancellationToken
,因此您应该在调用它时传递一个(即await Task.Delay(1000, cancellationToken)
),或者他们不会接受public static Task<T> WithCancellation<T>(this Task<T> task, CancellationToken cancellationToken)
{
return task.IsCompleted // fast-path optimization
? task
: task.ContinueWith(
completedTask => completedTask.GetAwaiter().GetResult(),
cancellationToken,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
}
。并且它们无法被取消(例如,等待I / O结果)。
然而,您可以使用此扩展方法放弃*这些任务:
await task.WithCancellation(cancellationToken);
用法:
{{1}}
*被放弃的任务不会被取消,但您的代码就像它有一样。它要么以结果/异常结束,要么永远保持活着。
答案 1 :(得分:8)
创建一个代表现有任务但具有额外取消令牌的新Task
非常简单。您只需要在任务上调用ContinueWith
,使用新标记,并在连续体中传播结果/异常。
public static Task WithCancellation(this Task task,
CancellationToken token)
{
return task.ContinueWith(t => t.GetAwaiter().GetResult(), token);
}
public static Task<T> WithCancellation<T>(this Task<T> task,
CancellationToken token)
{
return task.ContinueWith(t => t.GetAwaiter().GetResult(), token);
}
这允许您编写task.WithCancellation(cancellationToken)
以向任务添加令牌,然后您可以await
。
答案 2 :(得分:1)
这是另一种解决方案:
Task task;
CancellationToken token;
await Task.WhenAny(task, Task.Delay(Timeout.Infinite, token));
请参阅this answer,其中讨论了如何使用Task.Delay()
从Task
创建CancellationToken
。这是Task.WhenAny和Task.Delay的文档。