Simple WPF: C# Task异步任务的取消初探
最新内容优先发布于个人博客:小虎技术分享站,随后逐步搬运到博客园。
创作不易,如果觉得有用请在Github上为博主点亮一颗小星星吧!
C#中提供了CancellationTokenSource
来实现Task
的取消,方法就是在Task
异步循环中检测任务是否被取消。最近正在学习C#的任务异步模型,因此撰文以记之。
无法被取消的任务
原本以为Task
是运行在被.NET管理的线程池上的,可以直接通过Task.Run
传入的CancellationToken
进行取消。结果剧本不是我想的那样,这样根本停不下来。因此还是需要在循环中去判断任务是否被取消。
static async Task TaskCannotCancellationAsync()
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;
Task task = Task.Run(() =>
{
Console.WriteLine("Task Can not Cancellation Running...");
Thread.Sleep(1000);
Console.WriteLine("Task Can not Cancellation Running...");
Console.WriteLine("Task Finished");
}, cancellationTokenSource.Token);
cancellationTokenSource.Token.Register(() => Console.WriteLine("Cancel Task."));
cancellationTokenSource.CancelAfter(500);
await task;
}
解下来介绍正确的可以被取消的异步任务写法。
基于异常的任务取消
我们在Task
的任务循环中检测Token
是否被取消。而取消之后就抛出异常,通过异常处理来中断原有的任务。
static async Task TaskCancellationAsync()
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken token = cancellationTokenSource.Token;
Task task = Task.Run(async () =>
{
token.ThrowIfCancellationRequested();
bool moreToDo = true;
while (moreToDo)
{
Console.WriteLine("Task Cancellation Running...");
if (token.IsCancellationRequested)
{
token.ThrowIfCancellationRequested();
}
await Task.Delay(1000);
}
await Task.Delay(1000);
Console.WriteLine("Task Finished");
}, cancellationTokenSource.Token);
cancellationTokenSource.Token.Register(() => Console.WriteLine("Cancel Task."));
cancellationTokenSource.CancelAfter(500);
try
{
await task;
}
catch (OperationCanceledException e)
{
Console.WriteLine($"{nameof(OperationCanceledException)} thrown with message: {e.Message}");
}
finally
{
cancellationTokenSource.Dispose();
}
}
取消线程循环
既然我们可以这样取消一个死循环,那么博主就想试试看CancellationTokenSource
是否可以用于取消一个普通的线程。
static void ThreadProc(object? token)
{
CancellationToken? cancellationToken = (CancellationToken?)token;
while (!(cancellationToken?.IsCancellationRequested ?? true))
{
Console.WriteLine("ThreadMethod Working...");
Thread.Sleep(100);
}
}
static void ThreadAsync()
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
Thread thread = new Thread(new ParameterizedThreadStart(ThreadProc));
thread.Start(cancellationTokenSource.Token);
cancellationTokenSource.CancelAfter(500);
}
测试后发现这么写也可以实现线程工作循环的取消。
完整的实验输出效果
参考链接
https://cloud.tencent.com/developer/article/1895682
https://www.cnblogs.com/shanfeng1000/p/13402152.html
https://learn.microsoft.com/zh-cn/dotnet/standard/threading/cancellation-in-managed-threads