.Net中異步任務(wù)的取消和監(jiān)控的具體實(shí)現(xiàn)
相關(guān)類(lèi)型:
- CancellationTokenSource 主要用來(lái)創(chuàng)建或取消令牌
- CancellationToken 監(jiān)聽(tīng)令牌狀態(tài),注冊(cè)令牌取消事件
- OperationCanceledException 令牌被取消時(shí)拋出的異常,可以由監(jiān)聽(tīng)者自主決定是否拋出異常
CancellationTokenSource
創(chuàng)建令牌:
CancellationTokenSource cts = new CancellationTokenSource() CancellationToken token=cts.Token;
取消釋放令牌:
cts.Cancel();
CancellationToken
監(jiān)聽(tīng)令牌取消事件:
token.Register(() => Console.WriteLine("令牌被取消"));
判斷令牌是否取消
//返回一個(gè)bool,如果令牌被取消為true token.IsCancellationRequested //如果token被取消則拋出異常,內(nèi)部實(shí)現(xiàn)其實(shí)就是判斷IsCancellationRequested token.ThrowIfCancellationRequested()=>{ if(token.IsCancellationRequested){ throw new OperationCanceledException(); } }
代碼示例
下面模擬一個(gè)文件下載的任務(wù),在未下載完成后下載任務(wù)被取消
public void Run() { CancellationTokenSource cts = new CancellationTokenSource(); Task.Run(() => { //等待兩秒后取消,模擬的是用戶(hù)主動(dòng)取消下載任務(wù) Thread.Sleep(2000); cts.Cancel(); }); try { var size = DownloadFile(cts.Token); Console.WriteLine("文件大?。? + size); } catch (OperationCanceledException) { Console.WriteLine("下載失敗"); }finally{ cts.Dispose(); } Thread.Sleep(2000); } /// <summary> /// 模擬下載文件,下載文件需要五秒 /// </summary> /// <returns></returns> public int DownloadFile(CancellationToken token) { token.Register(() => { System.Console.WriteLine("監(jiān)聽(tīng)到取消事件"); }); Console.WriteLine("開(kāi)始下載文件"); for (int i = 0; i < 5; i++) { token.ThrowIfCancellationRequested(); Console.WriteLine(i.ToString()); Thread.Sleep(1000); } Console.WriteLine("文件下載完成"); return 100; }
輸出結(jié)果:
開(kāi)始下載文件
0
1
監(jiān)聽(tīng)到取消事件
下載失敗
思考
為什么要將CancellationToken和CancellationTokenSource分為兩個(gè)類(lèi)呢,直接一個(gè)CancellationToken又可以取消又可以判斷狀態(tài)注冊(cè)啥的不是更好,更方便?
其實(shí)每種類(lèi)的設(shè)計(jì)和實(shí)現(xiàn)都可以有很多不同的策略,CTS和CT從這個(gè)兩個(gè)類(lèi)提供的為數(shù)不多的公開(kāi)方法中就可以看出,CTS用來(lái)控制Token的生成和取消等生命周期狀態(tài),CT只能用來(lái)監(jiān)聽(tīng)和判斷,無(wú)法對(duì)Token的狀態(tài)進(jìn)行改變。
所以這種設(shè)計(jì)的目的就是關(guān)注點(diǎn)分離。限制了CT的功能,避免Token在傳遞過(guò)程中被不可控的因素取消造成混亂。
關(guān)聯(lián)令牌
繼續(xù)拿上面的示例來(lái)說(shuō),示例中實(shí)現(xiàn)了從外部控制文件下載功能的終止。
如果要給文件下載功能加一個(gè)超時(shí)時(shí)間的限制,此時(shí)可以增加一個(gè)控制超時(shí)時(shí)間的token,將外部傳來(lái)的token和內(nèi)部token 關(guān)聯(lián)起來(lái)變?yōu)橐粋€(gè)token
只需要將DownloadFile()函數(shù)做如下改造即可
public int DownloadFile(CancellationToken externalToken) { //通過(guò)構(gòu)造函數(shù)設(shè)置TokenSource一秒之后調(diào)用Cancel()函數(shù) var timeOutToken = new CancellationTokenSource(new TimeSpan(0, 0, 1)).Token; using (var linkToken = CancellationTokenSource.CreateLinkedTokenSource(externalToken, timeOutToken)) { Console.WriteLine("開(kāi)始下載文件"); for (int i = 0; i < 5; i++) { linkToken.Token.ThrowIfCancellationRequested(); Console.WriteLine(i.ToString()); Thread.Sleep(1000); } Console.WriteLine("文件下載完成"); return 100; } }
此時(shí)不論是externalToken取消,或是timeOutToken取消,都會(huì)觸發(fā)linkToken的取消事件
CancellationChangeToken
CancellationChangeToken主要用來(lái)監(jiān)測(cè)目標(biāo)變化,需配合ChangeToken使用。從功能場(chǎng)景來(lái)說(shuō),其實(shí)ChangeToken的功能和事件似乎差不多,當(dāng)監(jiān)控的目標(biāo)發(fā)生了變化,監(jiān)聽(tīng)者去做一系列的事情。
但是事件的話(huà),監(jiān)聽(tīng)者需要知道目標(biāo)的存在,就是如果A要注冊(cè)B的事件,A是要依賴(lài)B的。
CancellationChangeToken是基于CancellationToken來(lái)實(shí)現(xiàn)的,可以做到依賴(lài)于Token而不直接依賴(lài)被監(jiān)聽(tīng)的類(lèi)
創(chuàng)建CancellationChangeToken:
new CancellationChangeToken(new CancellationTokenSource().Token)
監(jiān)聽(tīng)Token變動(dòng)
new CancellationChangeToken(cts.Token).RegisterChangeCallback(obj => Console.WriteLine("token 變動(dòng)"), null);
CancellationChangeToken只是把CancellationToken包裝了一層。RegisterChangeCallback最終也是監(jiān)聽(tīng)的CancellationToken的IsCancellationRequested狀態(tài)。
所以就有個(gè)問(wèn)題,代碼寫(xiě)到這里,并不能實(shí)現(xiàn)每次內(nèi)部變動(dòng)都觸發(fā)回調(diào)事件。
因?yàn)镃T只會(huì)Cancel一次,對(duì)應(yīng)的監(jiān)聽(tīng)也會(huì)執(zhí)行一次。無(wú)法實(shí)現(xiàn)多次監(jiān)聽(tīng)
為了實(shí)現(xiàn)變化的持續(xù)監(jiān)聽(tīng),需要做兩個(gè)操作
- 讓Token在Cancel之后重新初始化
- 每次Cancel回調(diào)之后重新監(jiān)聽(tīng)新的Token
先上代碼,下面的代碼實(shí)現(xiàn)了每次時(shí)間變動(dòng)都會(huì)通知展示面板刷新時(shí)間的顯示
public void Run() { var bjDate = new BeijingDate(); DisplayDate(bjDate.GetChangeToken, bjDate.GetDate); Thread.Sleep(50000); } public void DisplayDate(Func<IChangeToken> getChangeToken, Func<DateTime> getDate) { ChangeToken.OnChange(getChangeToken, () => Console.WriteLine("當(dāng)前時(shí)間:" + getDate())); } public class BeijingDate { private CancellationTokenSource cts; private DateTime date; public BeijingDate() { cts = new CancellationTokenSource(); var timer = new Timer(TimeChange, null, 0, 1000); } private void TimeChange(object state) { date = DateTime.Now; var old = cts; cts = new CancellationTokenSource(); old.Cancel(); } public DateTime GetDate() => date; public CancellationChangeToken GetChangeToken() { return new CancellationChangeToken(cts.Token); } }
在TimeChange()中修改了時(shí)間,重置了Token并將舊的Token取消
在DisplayDate中用ChangeToken.OnChange獲取對(duì)應(yīng)的Token并監(jiān)聽(tīng)
實(shí)現(xiàn)了DisplayData函數(shù)和BeijingDate這個(gè)類(lèi)的解耦
ChangeToken.OnChange 這個(gè)函數(shù)接收兩個(gè)參數(shù),一個(gè)是獲取Token的委托,一個(gè)是Token取消事件的響應(yīng)委托。
每次在處理完Token的取消事件后,他會(huì)重新調(diào)用第一個(gè)委托獲取Token,而此時(shí)我們已經(jīng)生成了新的Token,最終實(shí)現(xiàn)了持續(xù)監(jiān)控
到此這篇關(guān)于.Net中異步任務(wù)的取消和監(jiān)控的文章就介紹到這了,更多相關(guān).Net中異步任務(wù)的取消和監(jiān)控內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- .NET?Core跨平臺(tái)資源監(jiān)控工具CZGL.SystemInfo用法
- .NET程序性能監(jiān)控系統(tǒng)Elastic?AMP的使用方法
- 使用?HttpReports?監(jiān)控?.NET?Core?應(yīng)用程序的方法
- 使用NLog給Asp.Net Core做請(qǐng)求監(jiān)控的方法
- Asp.Net 5分鐘實(shí)現(xiàn)網(wǎng)頁(yè)實(shí)時(shí)監(jiān)控
- ASP.NET MVC5使用MiniProfiler監(jiān)控MVC性能
- CZGL.ProcessMetrics監(jiān)控.NET應(yīng)用
相關(guān)文章
ASP.NET?Core實(shí)現(xiàn)動(dòng)態(tài)獲取文件并下載
這篇文章介紹了ASP.NET?Core實(shí)現(xiàn)動(dòng)態(tài)獲取文件并下載的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-01-01Asp.net中處理一個(gè)站點(diǎn)不同Web應(yīng)用共享Session的問(wèn)題
Asp.net中處理一個(gè)站點(diǎn)不同Web應(yīng)用共享Session的問(wèn)題...2006-09-09ASP.NET MVC Webuploader實(shí)現(xiàn)上傳功能
這篇文章主要為大家詳細(xì)介紹了ASP.NET MVC Webuploader實(shí)現(xiàn)上傳功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09AspNetAjaxPager,Asp.Net通用無(wú)刷新Ajax分頁(yè)控件,支持多樣式多數(shù)據(jù)綁定
最近閑來(lái)沒(méi)事,總結(jié)了一些asp.net分頁(yè)經(jīng)驗(yàn),為使用方便現(xiàn)在寫(xiě)了一個(gè)可以通用的分頁(yè)控件:AspNetAjaxPager:,使用ajax技術(shù)實(shí)現(xiàn)無(wú)刷新分頁(yè),能夠控制所有數(shù)據(jù)綁定控件的分頁(yè),自己覺(jué)得效果還是挺不錯(cuò)的,現(xiàn)在奉獻(xiàn)給大家!2009-04-04Asp.Mvc?2.0實(shí)現(xiàn)用戶(hù)注冊(cè)實(shí)例講解(1)
這篇文章主要介紹了Asp.Mvc?2.0如何實(shí)現(xiàn)用戶(hù)注冊(cè),實(shí)例講解很細(xì)致,注冊(cè)功能是每個(gè)網(wǎng)站必不可少的組成部分,感興趣的的朋友可以參考下2015-08-08.Net中Task Parallel Library的進(jìn)階用法
這篇文章介紹了.Net中Task Parallel Library的進(jìn)階用法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-10-10VS2015 免費(fèi)插件Refactoring Essentials
Refactoring Essentials是一款用于代碼分析和重構(gòu)的開(kāi)源免費(fèi)VS2015插件,其功能豐富強(qiáng)大,必然會(huì)成為類(lèi)似Web Essentials這樣的必備插件。2015-07-07ASP.NET數(shù)據(jù)綁定之DataList控件實(shí)戰(zhàn)篇
這篇文章主要為大家介紹了ASP.NET數(shù)據(jù)綁定中的DataList控件,DataList控件以表的形式呈現(xiàn)數(shù)據(jù),通過(guò)該控件,您可以使用不同的布局來(lái)顯示數(shù)據(jù)記錄,對(duì)DataList控件感興趣的小伙伴們可以參考一下2016-01-01