Luk*_* Vo 7 .net c# asynchronous task
在微软70-483关于使用CancellationToken的考试的参考书中,取消信号的第一种方法是抛出异常,然后介绍第二种方法:
您还可以添加仅在取消任务时执行的继续任务,而不是捕获异常.在此任务中,您可以访问引发的异常,如果合适,您可以选择处理它.清单1-44显示了这样的延续任务的样子
这是列表1-44:
Task task = Task.Run(() =>
{
while (!token.IsCancellationRequested)
{
Console.Write("*");
Thread.Sleep(1000);
}
}, token).ContinueWith((t) =>
{
t.Exception.Handle((e) => true);
Console.WriteLine("You have canceled the task");
}, TaskContinuationOptions.OnlyOnCanceled);
Run Code Online (Sandbox Code Playgroud)
这是我的完整Main方法代码:
static void Main(string[] args)
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
var token = cancellationTokenSource.Token;
Task task = Task.Run(() =>
{
while (!token.IsCancellationRequested)
{
Console.Write("*");
Thread.Sleep(1000);
}
}, token).ContinueWith((t) =>
{
t.Exception.Handle((e) => true);
Console.WriteLine("You have canceled the task");
}, TaskContinuationOptions.OnlyOnCanceled);
Console.ReadLine();
cancellationTokenSource.Cancel();
task.Wait();
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
但是,与我所说的不同,当我按Enter时,异常(AggregationException)仍然会在task.Wait()调用时抛出到Main方法.此外,如果我删除该调用,第二个任务永远不会运行(不会抛出异常).有什么我做错了吗?是否可以在不使用的情况下处理异常try-catch?
要明确说明问题,您的第二个延续不执行,但您认为它应该:
static void Main(string[] args)
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
var token = cancellationTokenSource.Token;
Task task = Task.Run(() =>
{
while (!token.IsCancellationRequested)
{
Console.Write("*");
Thread.Sleep(1000);
}
}, token).ContinueWith((t) =>
{ // THIS
t.Exception.Handle((e) => true); // ISN'T
Console.WriteLine("You have canceled the task"); // EXECUTING
}, TaskContinuationOptions.OnlyOnCanceled);
Console.ReadLine();
cancellationTokenSource.Cancel();
task.Wait();
Console.ReadLine();
}
Run Code Online (Sandbox Code Playgroud)
第二个延续不执行,因为您必须使用token.ThrowIfCancellationRequested()才能触发它:
Task task = Task.Run(() =>
{
while (true)
{
token.ThrowIfCancellationRequested(); // <-- NOTICE
Console.Write("*");
Thread.Sleep(1000);
}
}, token).ContinueWith((t) =>
{
Console.WriteLine("From Continuation: " + t.Status);
Console.WriteLine("You have canceled the task");
}, TaskContinuationOptions.OnlyOnCanceled);
// OUTPUT:
// ***
// From Continuation: Canceled
// You have canceled the task
Run Code Online (Sandbox Code Playgroud)
第二延续被称为因为task.Status是Canceled.下一个片段不会触发第二个延续,因为task.Status它未设置为Canceled:
Task task = Task.Run(() =>
{
while (!token.IsCancellationRequested)
{
Console.Write("*");
Thread.Sleep(1000);
}
}, token).ContinueWith((t) =>
{
Console.WriteLine("From Continuation: " + t.Status);
Console.WriteLine("You have canceled the task");
}, TaskContinuationOptions.OnlyOnCanceled);
// OUTPUT:
// AggregationException
Run Code Online (Sandbox Code Playgroud)
如上所述,第二个延续没有被称为.让我们通过删除OnlyOnCanceled子句来强制执行:
Task task = Task.Run(() =>
{
while (!token.IsCancellationRequested)
{
Console.Write("*");
Thread.Sleep(1000);
}
}, token).ContinueWith((t) =>
{
Console.WriteLine("From Continuation: " + t.Status);
Console.WriteLine("You have NOT canceled the task");
}); // <-- OnlyOnCanceled is gone!
// OUTPUT:
// ***
// From Continuation: RanToCompletion
// You have NOT canceled the task
// (no AggregationException thrown)
Run Code Online (Sandbox Code Playgroud)
请注意,即使.Cancel()被调用,task.Status延续中的from也是RanToCompletion.还要注意没有AggregationException抛出.这表明只是.Cancel()从令牌源调用不会将任务状态设置为Canceled.
当仅.Cancel()调用.ThrowIfCancellationRequested()且未调用时,AggregationException实际上是成功取消任务的指示符.引用MSDN文章:
如果您正在等待
Task转换到Canceled状态,则抛出System.Threading.Tasks.TaskCanceledException异常(包含在AggregateException异常中).请注意,此异常表示成功取消而不是出现故障.因此,任务的Exception属性返回null.
这让我得出了一个圆满的结论:
t.Exception...我的所有代码都省略了您的行,因为成功取消后" 任务的Exception属性返回null ".清单1-44中应该省略该行.看起来他们正在混淆以下两种技术:
OnlyOnCanceled继续被调用,不会引发任何异常.OnlyOnCanceled没有调用继续,并且抛出了AggregationException以供您处理Task.Wait()免责声明:两个片段都是取消任务的有效方法,但它们可能存在我不知道的行为差异.
| 归档时间: |
|
| 查看次数: |
1869 次 |
| 最近记录: |