C# Task任务取消
需求:
在使用Blazor开发工具时,有个需求:
扫码登录页面需要不断轮询接口获取扫码状态,并在对应的状态下进行对应的操作:刷新、登录、跳转等;
此时,为了不阻塞前端的响应,需要我们开启一个线程进行状态检测,并在完成后结束线程任务;
方案:
使用取消令牌(CancellationTokenSource);
相对操作比较简单,需要结束时调用Cancel(),同时,在Task内部进行IsCancellationRequested状态监听、或者使用暴力调用ThrowIfCancellationRequested()(同样需要不间断的调用,Cancel后才可触发,本质上也是校验IsCancellationRequested状态);
var cts = new CancellationTokenSource();
var tk = cts.Token;
// 将CancellationToken传入action中,然后对其取消状态进行跟踪
_ = Task.Factory.StartNew(async tk =>
{
CancellationToken ct = (CancellationToken)tk;
while (true)
{
ct.ThrowIfCancellationRequested();
Console.WriteLine("循环中" + Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1000);
}
}, tk, TaskCreationOptions.LongRunning);
// OR
// 此处是对于取消注册个回调方法,在取消后进行调用
_ = Task.Factory.StartNew(async tk =>
{
var state = true;
CancellationToken ct = (CancellationToken)tk;
ct.Register(() =>
{
state = false;
});
while (state)
{
Console.WriteLine("循环中" + Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1000);
}
}, tk, TaskCreationOptions.LongRunning);
注意:
- 在使用Task.Run() 或 Task.Factory.StartNew()时,有个参数为传入CancellationToken,如:Run(Action, CancellationToken);该cancellationToken不会传递到Task内,更不会对Task内不造成影响,该cancellationToken 只是用于取消Run() 或 StartNew();
- ck.Register可进行多次,构成链表执行,链表为倒叙的(最先注册的最后执行);
扩展
CancellationTokenSource 具体实现源码解析:浅谈C#取消令牌CancellationTokenSource
相关项目:WeComLoad Demo