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

时间:2014-09-02 21:35:18

标签: c# .net task-parallel-library async-await

因此,task.Wait()可以转换为await task。当然,语义是不同的,但这大致是我如何将带有Waits的阻塞代码转换为带有awaits的异步代码。

我的问题是如何将task.Wait(CancellationToken)转换为相应的await声明?

3 个答案:

答案 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.WhenAnyTask.Delay的文档。