需求:
在使用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