【发布时间】:2017-05-07 16:23:28
【问题描述】:
我试图优雅地放弃长时间运行的操作,这些操作本质上是一系列下载数据和更新 UI。
例如,用户选择了一个项目,它的详细信息开始从服务器加载。但随后他改变主意并选择了另一个项目。先前的操作被取消,并且该过程重新开始。然而,有可能已经接收到数据并将继续发布到消息循环以供执行。问题是async/await是否有可能。
Stephen Toub 有一个blog post,他提供了这个扩展:
public static async Task<T> WithCancellation<T>(
this Task<T> task, CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<bool>();
using(cancellationToken.Register(
s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs))
if (task != await Task.WhenAny(task, tcs.Task))
throw new OperationCanceledException(cancellationToken);
return await task;
}
在return语句中return await task任务已经完成。
如果我在 UI 线程中等待任务:
var result = await task.WithCancellation(token);
...continuation...
return await task; 在 UI 线程中执行。
但是continuation 是与等待的异步方法的延续同步运行还是单独发布到消息循环中?
同步执行可以避免取消(用户选择另一个项目)发生在消息队列中出现延续之后的情况。如果不是这种情况,那么我必须另外检查:
var result = await task.WithCancellation(token);
token.ThrowIfCancellationRequested();
...continuation...
【问题讨论】:
-
继续返回消息循环。所以是的,可以在很短的时间内取消令牌
标签: c# wpf winforms asynchronous async-await