【发布时间】:2017-09-05 12:28:31
【问题描述】:
我有以下示例:
public void Run()
{
var ctc = new CancellationTokenSource();
try
{
DoAsync(ctc).Wait();
Console.WriteLine("Done");
}
catch (AggregateException exception)
{
Console.WriteLine("Inside try-catch block");
Console.WriteLine();
Console.WriteLine(exception);
exception.Handle(ex =>
{
Console.WriteLine(ex.Message);
return true;
});
}
}
private async Task DoAsync(CancellationTokenSource ctc)
{
Console.WriteLine("DoAsync started");
await Task.Run(() =>
Console.WriteLine("DoAsync Run"),
ctc.Token
)
.ContinueWith(antecedent =>
Console.WriteLine("DoAsync Run cancelled"),
TaskContinuationOptions.OnlyOnCanceled
);
Console.WriteLine("DoAsync finished");
}
我创建了一个方法 (DoAsync),它执行一些异步工作并且可以随时取消。
如您所见,Task.Run 获得了一个取消令牌。出于这个原因,我使用 continuationOptions = TaskContinuationOptions.OnlyOnCanceled 创建了延续任务。
因此,我希望仅在请求取消时调用延续任务,而在其他情况下 - 被忽略。
但在我的实现任务中,由 ContinueWith 返回的任务在其前面的任务未被取消时会引发异常:
DoAsync started
DoAsync Run
Inside try-catch block
System.AggregateException...
A task was canceled.
我可以通过添加另一个 ContinueWith 来解决此问题,如下例所示:
await Task.Run(() =>
Console.WriteLine("DoAsync Run"),
ctc.Token
)
.ContinueWith(antecedent =>
Console.WriteLine("DoAsync Run cancelled"),
TaskContinuationOptions.OnlyOnCanceled
)
.ContinueWith(antecedent => { });
而且这段代码不会抛出任何异常。
但是我可以使用单个 ContinueWith 正确处理取消吗?
【问题讨论】:
-
你试过只传token,不传token源吗?
-
@Fildor,我同意我应该传递令牌而不是令牌源。但它是如何解决我的问题的呢?
-
它可能不会。这就是为什么它只是一个评论。但也许它会减少副作用。我看不出你的代码不能按预期工作的明显原因......(还)
-
您是否有理由组合 async/await 并继续?您可以在 await 周围使用 try/catch 重新创建它并捕获
catch (OperationCanceledException ex) when ex.CancellationToken.Equals(ctc.Token) { Console.WriteLine("DoAsync Run cancelled"); } -
@VladyslavYefremov:你根本不应该使用
ContinueWith。将await与try/catch一起使用会产生更易于维护的代码。
标签: c# .net asynchronous task-parallel-library cancellationtokensource