如何将task.Wait(CancellationToken)转换为await语句?

mar*_*ark 12 .net c# task-parallel-library async-await

所以,task.Wait()可以转化为await task.当然,语义是不同的,但这大致是我将阻塞代码Waits转换为异步代码的方法awaits.

我的问题是如何转变task.Wait(CancellationToken)为各自的await声明?

i3a*_*non 9

await用于异步方法/委托,它们接受a CancellationToken,因此你应该在调用它时传递一个(即await Task.Delay(1000, cancellationToken)),或者它们不传递它们,它们实际上不能被取消(例如等待I/O结果).

但是,您可以使用此扩展方法放弃*这些类型的任务:

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);
}
Run Code Online (Sandbox Code Playgroud)

用法:

await task.WithCancellation(cancellationToken);
Run Code Online (Sandbox Code Playgroud)

*被放弃的任务不会被取消,但您的代码就像它有一样.它要么以结果/异常结束,要么永远保持活力.

  • @mark那是因为`async-await`需要不同的心态."常规"委托任务和"承诺"异步任务,尽管它们共享一种类型,但却是完全不同的概念...... [两种任务类型](http://blog.stephencleary.com/2014/04/a-tour-的任务部分-O-overview.html) (2认同)

Ser*_*rvy 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);
}
Run Code Online (Sandbox Code Playgroud)

这允许您编写task.WithCancellation(cancellationToken)以向任务添加令牌,然后您可以执行此操作await.

  • @mark 事实并非如此。它取消您正在等待的延续。 (2认同)