亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C# CancellationToken和CancellationTokenSource的用法詳解

 更新時間:2021年06月24日 10:11:44   作者:沒有星星的夏季  
做了.net core之后,發(fā)現(xiàn)CancellationToken用的越來越平凡了。這也難怪,原來.net framework使用異步的不是很多,而.net core首推異步編程,到處可以看到Task的影子,而CancellationToken正好是異步Task的一個控制器,所以花點時間做個筆記

CancellationToken

  CancellationToken有一個構(gòu)造函數(shù),可以傳入一個bool類型表示當(dāng)前的CancellationToken是否是取消狀態(tài)。另外,因為CancellationToken是一個結(jié)構(gòu)體,所以它還有一個空參數(shù)的構(gòu)造函數(shù)?!?/p>

    public CancellationToken();//因為是結(jié)構(gòu)體,才有空構(gòu)造函數(shù),不過沒什么作用
    public CancellationToken(bool canceled);

   屬性如下:  

    //靜態(tài)屬性,獲取一個空的CancellationToken,這個CancellationToken注冊的回調(diào)方法不會被觸發(fā),作用類似于使用空構(gòu)造函數(shù)得到的CancellationToken
    public static CancellationToken None { get; }
    //表示當(dāng)前CancellationToken是否可以被取消
    public bool CanBeCanceled { get; }
    //表示當(dāng)前CancellationToken是否已經(jīng)是取消狀態(tài)
    public bool IsCancellationRequested { get; }
    //和CancellationToken關(guān)聯(lián)的WaitHandle對象,CancellationToken注冊的回調(diào)方法執(zhí)行時通過這個WaitHandle實現(xiàn)的
    public WaitHandle WaitHandle { get; }

  常用方法:  

    //往CancellationToken中注冊回調(diào)
    public CancellationTokenRegistration Register(Action callback);
    public CancellationTokenRegistration Register(Action callback, bool useSynchronizationContext);
    public CancellationTokenRegistration Register([NullableAttribute(new[] { 1, 2 })] Action<object?> callback, object? state);
    public CancellationTokenRegistration Register([NullableAttribute(new[] { 1, 2 })] Action<object?> callback, object? state, bool useSynchronizationContext);
    //當(dāng)CancellationToken處于取消狀態(tài)是,拋出System.OperationCanceledException異常
    public void ThrowIfCancellationRequested();

  常用的注冊回調(diào)的方法是上面4個Register方法,其中callback是回調(diào)執(zhí)行的委托,useSynchronizationContext表示是否使用同步上下文,state是往回調(diào)委托中傳的參數(shù)值

  另外,Register方法會返回一個CancellationTokenRegistration結(jié)構(gòu)體,當(dāng)注冊回調(diào)之后,可以調(diào)用CancellationTokenRegistration的Unregister方法來取消注冊,這個Unregister方法會返回一個bool值,當(dāng)成功取消時返回true,當(dāng)取消失?。ū热缁卣{(diào)已執(zhí)行)將返回false:  

    CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    var cancellationTokenRegistration = cancellationTokenSource.Token.Register(() =>
    {
        Console.WriteLine("Canceled");//這里將不會執(zhí)行輸出
    });

    //cancellationTokenSource.Cancel();
    //var result = cancellationTokenRegistration.Unregister();//result = false

    var result = cancellationTokenRegistration.Unregister();//result = true
   cancellationTokenSource.Cancel();

   上面提到,CancellationToken可以使用構(gòu)造函數(shù)直接構(gòu)造,同時可以傳入一個參數(shù),表示當(dāng)前的狀態(tài),需要注意的是,CancellationToken的狀態(tài)最多可以改變一次,也就是從未取消變成已取消。

  如果構(gòu)造時傳入true,也就是說CancellationToken是已取消狀態(tài),這個時候注冊的回調(diào)都會立即執(zhí)行: 

    CancellationToken cancellationToken = new CancellationToken(true);
    cancellationToken.Register(() =>
    {
        Console.WriteLine("Canceled");//這里會立即執(zhí)行輸出Canceled
    });

  但如果構(gòu)造時傳入的是false,說明CancellationToken處于未取消狀態(tài),這時候注冊的回到都會處于一個待觸發(fā)狀態(tài):

    CancellationToken cancellationToken = new CancellationToken(false);
    cancellationToken.Register(() =>
    {
        Console.WriteLine("Canceled");//這里不會立即執(zhí)行輸出
    });

通過Register方法注冊的服務(wù)只會執(zhí)行一次!

  但一般的,如果傳入false構(gòu)造出來的CancellationToken,可以認(rèn)為是不會觸發(fā)的,因為它沒有觸發(fā)的方法!所以一般的,我們都不會直接使用構(gòu)造函數(shù)創(chuàng)建CancellationToken,而是使用CancellationTokenSource對象來獲取一個CancellationToken

CancellationTokenSource

  CancellationTokenSource可以理解為CancellationToken的控制器,控制它什么時候變成取消狀態(tài)的一個對象,它有一個CancellationToken類型的屬性Token,只要CancellationTokenSource創(chuàng)建,這個Token也會被創(chuàng)建,同時Token會和這個CancellationTokenSource綁定

    //表示Token是否已處于取消狀態(tài)
    public bool IsCancellationRequested { get; }
    //CancellationToken 對象
    public CancellationToken Token { get; }

  可以直接創(chuàng)建一個CancellationTokenSource對象,同時指定一個時間段,當(dāng)過了這段時間后,CancellationTokenSource就會自動取消了。

  CancellationTokenSource的取消有4個方法:  

    //立刻取消
    public void Cancel();
    //立刻取消
    public void Cancel(bool throwOnFirstException);
    //延遲指定時間后取消
    public void CancelAfter(int millisecondsDelay);
    //延遲指定時間后取消
    public void CancelAfter(TimeSpan delay);

  Cancel和兩個CancelAfter方法沒什么特別的,主要就是有一個延遲的效果,需要注意的是Cancel的兩個重載之間的區(qū)別。

  首先,上面說道,CancellationToken狀態(tài)只能改變一次(從未取消變成已取消),當(dāng)CancellationToken時已取消狀態(tài)時,每次往其中注冊的回調(diào)都會立刻執(zhí)行!當(dāng)處于未取消狀態(tài)時,注冊進(jìn)去的回調(diào)都會等待執(zhí)行。

  需要注意的是,當(dāng)在未取消狀態(tài)下注冊多個回調(diào)時,它們在執(zhí)行時是一個類似棧的結(jié)構(gòu)順序,先注冊后執(zhí)行。

  而CancellationToken的Register可以注冊多個回調(diào),那他們可能都會拋出異常,throwOnFirstException參數(shù)表示在第一次報錯時的處理行為.

  throwOnFirstException = true 表示立即拋出當(dāng)前發(fā)生的異常,后續(xù)的回調(diào)將會取消執(zhí)行  

    CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    try
    {
        cancellationTokenSource.Token.Register(() =>
        {
            throw new Exception("1");
        });
        cancellationTokenSource.Token.Register(() =>
        {
            throw new Exception("2");//不會執(zhí)行
        });

        cancellationTokenSource.Cancel(true);
    }
    catch (Exception ex)
    {
        //ex is System.Exception("1")
    }

   throwOnFirstException = false 表示跳過當(dāng)前回調(diào)的異常,繼續(xù)執(zhí)行生效的回調(diào),等所有的回調(diào)執(zhí)行完成之后,再將所有的異常打包成一個System.AggregateException異常拋出來!

    CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    try
    {
        cancellationTokenSource.Token.Register(() =>
        {
            throw new Exception("1");
        });
        cancellationTokenSource.Token.Register(() =>
        {
            throw new Exception("2");
        });

        cancellationTokenSource.Cancel(false);//相當(dāng)于cancellationTokenSource.Cancel()
    }
    catch (Exception ex)
    {
        //ex is System.AggregateException:[Exception("2"),Exception("1")]
    }

   CancellationTokenSource還可以與其它CancellationToken關(guān)聯(lián)起來,生成一個新的CancellationToken,當(dāng)其他CancellationToken取消時,會自動觸發(fā)當(dāng)前的CancellationTokenSource執(zhí)行取消動作!  

使用場景一

  當(dāng)我們創(chuàng)建異步操作時,可以傳入一個CancellationToken,當(dāng)異步操作處于等待執(zhí)行狀態(tài)時,可以通過設(shè)置CancellationToken為取消狀態(tài)將異步操作取消執(zhí)行:  

    CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    var task = new Task(() =>
    {
        Thread.Sleep(1500);//執(zhí)行了2秒中代碼
        Console.WriteLine("Execute Some Code");
    }, cancellationTokenSource.Token);

    task.Start();//啟動,等待調(diào)度執(zhí)行

    //發(fā)現(xiàn)不對,可以取消task執(zhí)行
    cancellationTokenSource.Cancel();
    Thread.Sleep(1000);//等待1秒
    Console.WriteLine("Task狀態(tài):" + task.Status);//Canceled

   但是經(jīng)常的,我們的取消動作可能不會那么及時,如果異步已經(jīng)執(zhí)行了,再執(zhí)行取消時無效的,這是就需要我們自己在異步委托中檢測了:  

    CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    var task = new Task(() =>
    {
        Thread.Sleep(1500);//執(zhí)行了2秒中代碼
        cancellationTokenSource.Token.ThrowIfCancellationRequested();
        Console.WriteLine("Execute Some Code");
    }, cancellationTokenSource.Token);

    task.Start();//啟動,等待調(diào)度執(zhí)行

    Thread.Sleep(1000);////一段時間后發(fā)現(xiàn)不對,可以取消task執(zhí)行
    cancellationTokenSource.Cancel();
    Thread.Sleep(1000);//等待1秒
    Console.WriteLine("Task狀態(tài):" + task.Status);//Canceled

使用場景二

   有時,我們希望在觸發(fā)某個時間后,可以執(zhí)行某些代碼功能,但是在異步環(huán)境下,我們不能保證那些要執(zhí)行的代碼是否已準(zhǔn)備好了,比如我們有一個Close方法,當(dāng)調(diào)用Close后表示是關(guān)閉狀態(tài),如果我們相當(dāng)程序處于關(guān)閉狀態(tài)時執(zhí)行一些通知,一般的,我們可能是想到采用事件模型,或者在Close方法傳入事件委托,或者采用一些諸如模板設(shè)計這樣的模型去實現(xiàn): 

    class Demo
    {
        public void Close(Action callback)
        {
            //關(guān)閉
            Thread.Sleep(3000);

            callback?.Invoke();//執(zhí)行通知
        }
    }

  或者  

    class Demo
    {
        public event Action Callback;

        public void Close()
        {
            //關(guān)閉
            Thread.Sleep(3000);

            Callback?.Invoke();//執(zhí)行通知
        }
    }

  但是這就有問題了,如果是傳入?yún)?shù)或者采用事件模型,因為前面說過了,如果在異步環(huán)境下,我們不能保證那些要執(zhí)行的代碼是否已準(zhǔn)備好了,也許在執(zhí)行Close方法時,程序還未注冊回調(diào)。

  這個時候就可以使用CancellationToken來解決這個問題:  

  主需要往Token屬性中注冊回調(diào)而無需關(guān)注Close什么時候執(zhí)行了

使用場景三

  有時候,我們寫一個異步無限循環(huán)的方法去處理一些問題,而我們希望可以在方法外來停止它這個時候,我們就可以通過返回CancellationTokenSource來實現(xiàn)了:  

        public CancellationTokenSource Listen()
        {
            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

            //循環(huán)調(diào)度執(zhí)行
            Task.Run(() =>
            {
                while (true)
                {
                    cancellationTokenSource.Token.ThrowIfCancellationRequested();

                    //循環(huán)執(zhí)行一些操作
                    Thread.Sleep(1000);
                    Console.WriteLine("Run");
                }
            });

            return cancellationTokenSource;
        }

以上就是C# CancellationToken和CancellationTokenSource的用法詳解的詳細(xì)內(nèi)容,更多關(guān)于C# CancellationToken和CancellationTokenSource的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#實現(xiàn)為視頻添加水印

    C#實現(xiàn)為視頻添加水印

    這篇文章主要為大家詳細(xì)介紹了C#如何使用ffmpeg命令,分別實現(xiàn)給視頻添加圖片水印以及文字水印,文中的示例代講解詳細(xì),感興趣的可以了解一下
    2023-01-01
  • unity實現(xiàn)屏幕上寫字效果

    unity實現(xiàn)屏幕上寫字效果

    這篇文章主要為大家詳細(xì)介紹了unity實現(xiàn)屏幕上寫字效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • C#二進(jìn)制序列化實例分析

    C#二進(jìn)制序列化實例分析

    這篇文章主要介紹了C#二進(jìn)制序列化,實例分析了C#二進(jìn)制序列化的方法,代碼中有較為詳盡的注釋說明,便于理解,需要的朋友可以參考下
    2015-05-05
  • C#實現(xiàn)梳排序的使用示例

    C#實現(xiàn)梳排序的使用示例

    梳排序算法是一種改進(jìn)的冒泡排序算法,它通過調(diào)整冒泡排序的間隔來提高排序的效率,本文主要介紹了C#實現(xiàn)梳排序的使用示例,感興趣的可以了解一下
    2023-11-11
  • C#實現(xiàn)AI五子棋游戲的示例代碼

    C#實現(xiàn)AI五子棋游戲的示例代碼

    這篇文章主要為大家詳細(xì)介紹了C#如何智能AI五子棋游戲中的人工下棋操作以及對應(yīng)的機(jī)器操作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-11-11
  • C#中的Linq?to?JSON操作詳解

    C#中的Linq?to?JSON操作詳解

    本文詳細(xì)講解了C#中的Linq?to?JSON操作,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • C#開發(fā)微信公眾號接口開發(fā)

    C#開發(fā)微信公眾號接口開發(fā)

    這篇文章主要介紹了C#微信公眾號接口開發(fā),靈活利用網(wǎng)頁授權(quán)、帶參數(shù)二維碼、模板消息,提升用戶體驗之完成用戶綁定個人微信及驗證碼獲取,需要的朋友可以參考下
    2015-07-07
  • C# 延遲Task.Delay()和Thread.Sleep()的具體使用

    C# 延遲Task.Delay()和Thread.Sleep()的具體使用

    Thread.Sleep()是同步延遲,Task.Delay()是異步延遲,本文主要介紹了C# 延遲Task.Delay()和Thread.Sleep()的具體使用,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-01-01
  • c#通過app.manifest使程序以管理員身份運(yùn)行

    c#通過app.manifest使程序以管理員身份運(yùn)行

    通常我們使用c#編寫的程序不會彈出這個提示,也就無法以管理員身分運(yùn)行。微軟的操作系統(tǒng)使用微軟的產(chǎn)品方法當(dāng)然是有的,通過app.manifest配置可以使程序打開的時候,彈出UAC提示需要得到允許才可以繼續(xù),這樣就獲得了管理員的權(quán)限來執(zhí)行程序
    2015-01-01
  • 詳解C#借助.NET框架中的XmlTextReader類讀取XML的方法

    詳解C#借助.NET框架中的XmlTextReader類讀取XML的方法

    這篇文章主要介紹了詳解借助.NET框架中的XmlTextReader類讀取XML的方法,這種方式的執(zhí)行效率還是比較令人滿意的,需要的朋友可以參考下
    2016-04-04

最新評論