最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#異步編程由淺入深(二)之Async/Await的使用

 更新時間:2022年03月04日 10:09:59   作者:白煙染黑墨  
這篇文章主要介紹了C#異步編程由淺入深(二)之Async/Await的作用,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

  考慮到直接講實現(xiàn)一個類Task庫思維有點跳躍,所以本節(jié)主要講解Async/Await的本質(zhì)作用(解決了什么問題),以及Async/Await的工作原理。實現(xiàn)一個類Task的庫則放在后面講。首先回顧一下上篇博客的場景。

 class Program
    {

        public static string GetMessage()
        {
            return Console.ReadLine();
        }
        public static  string TranslateMessage(string msg)
            return msg;
        public static  void DispatherMessage(string msg)
            switch (msg)
            {
                case "MOUSE_MOVE":
                    {
                        OnMOUSE_MOVE(msg);
                        break;
                    }
                case "MOUSE_DOWN":
                        OnMouse_DOWN(msg);
                default:
                    break;
            }
        public static void OnMOUSE_MOVE(string msg)
            Console.WriteLine("開始繪制鼠標形狀");
        public static int Http()
            Thread.Sleep(1000);//模擬網(wǎng)絡IO延時
            return 1;
        public static void HttpAsync(Action<int> action,Action error)
            //這里我們用另一個線程來實現(xiàn)異步IO,由于Http方法內(nèi)部是通過Sleep來模擬網(wǎng)絡IO延時的,這里也只能通過另一個線程來實現(xiàn)異步IO
            //但記住,多線程是實現(xiàn)異步IO的一個手段而已,它不是必須的,后面會講到如何通過一個線程來實現(xiàn)異步IO。
            Thread thread = new Thread(() => 
                try
                {
                    int res = Http();
                    action(res);
                }
                catch
                    error();
      
            });
            thread.Start();
        public static Task<int> HttpAsync()
            return Task.Run(() => 
                return Http();
        public static void OnMouse_DOWN(string msg)
            HttpAsync()
                .ContinueWith(t => 
                    if(t.Status == TaskStatus.Faulted)
                    }else if(t.Status == TaskStatus.RanToCompletion)
                        Console.WriteLine(1);
                        //做一些工作
                })
                    if (t.Status == TaskStatus.Faulted)
                    else if (t.Status == TaskStatus.RanToCompletion)
                        Console.WriteLine(2);
                        Console.WriteLine(3);
                });
        static void Main(string[] args)
            while (true)
                string msg = GetMessage();
                if (msg == "quit") return;
                string m = TranslateMessage(msg);
                DispatherMessage(m);
    }

  在OnMouse_DOWN這個處理函數(shù)中,我們使用Task的ContinueWith函數(shù)進行鏈式操作,解決了回調(diào)地獄問題,但是總感覺有點那么不爽,我們假想有個關鍵字await它能實現(xiàn)以下作用:首先await必須是Task類型,必須是Task類型的(其實不是必要條件,后面會講到)原因是保證必須有ContinueWith這個函數(shù),如果Task沒有返回值,則把await后面的代碼放到Task中的ContinueWith函數(shù)體內(nèi),如果有返回值,則把Await后的結果轉(zhuǎn)化為訪問Task.Result屬性,文字說的可能不明白,看下示例代碼

//無返回值轉(zhuǎn)換前
public async void Example()
{
    Task t = Task.Run(() =>
    {
        Thread.Sleep(1000);
    });
    await t;
    //做一些工作
}
//無返回值轉(zhuǎn)換后
public void Example()
    t.ContinueWith(task => 
        //做一些工作

//有返回值轉(zhuǎn)換前
    Task<int> t = Task.Run<int>(() =>
        return 1;
    int res = await t;
    //使用res做一些工作
//有返回值轉(zhuǎn)換后
        //使用task.Result做一些工作

  看起來不錯,但至少有以下問題,如下:

  • 該種轉(zhuǎn)換方法不能很好的轉(zhuǎn)換Try/Catch結構
  • 在循環(huán)結構中使用await不好轉(zhuǎn)換
  • 該實現(xiàn)與Task類型緊密聯(lián)系

  一二點是我自己認為的,但第三點是可以從擴展async/await這點被證明的。但無論怎樣,async/await只是對方法按照一定的規(guī)則進行了變換而已,它并沒有什么特別之處,具體來講,就是把Await后面要執(zhí)行的代碼放到一個類似ContinueWith的函數(shù)中,在C#中,它是以狀態(tài)機的形式表現(xiàn)的,每個狀態(tài)都對應一部分代碼,狀態(tài)機有一個MoveNext()方法,MoveNext()根據(jù)不同的狀態(tài)執(zhí)行不同的代碼,然后每個狀態(tài)部分對應的代碼都會設置下一個狀態(tài)字段,然后把自身的MoveNext()方法放到類似ContinueWith()的函數(shù)中去執(zhí)行,整個狀態(tài)機由回調(diào)函數(shù)推動。我們嘗試手動轉(zhuǎn)換以下async/await方法。

public static Task WorkAsync()
{
    return Task.Run(() => 
    {
        Thread.Sleep(1000);
        Console.WriteLine("Done!");
    });
}
public static async void Test()
{
    Console.WriteLine("步驟1");
    await WorkAsync();
    Console.WriteLine("步驟2");
    await WorkAsync();
    Console.WriteLine("步驟3");
}

  手動寫一個簡單的狀態(tài)機類

public class TestAsyncStateMachine
    {
        public int _state = 0;
        public void Start() => MoveNext();
        public void MoveNext()
        {
            switch(_state)
            {
                case 0:
                    {
                        goto Step0;
                    }
                case 1:
                        goto Step1;
                default:
                        Console.WriteLine("步驟3");
                        return;
            }

        Step0:
                Console.WriteLine("步驟1");
                _state = 1;
                WorkAsync().ContinueWith(t => this.MoveNext());
                return;
        Step1:
                _state = -1;
                Console.WriteLine("步驟2");
        }
    }

  而Test()方法則變成了這樣

public static void Test()
{
    new TestAsyncStateMachine().Start();
}

  注意Test()方法返回的是void,這意味這調(diào)用方將不能await Test()。如果返回Task,這個狀態(tài)機類是不能正確處理的,如果要正確處理,那么狀態(tài)機在Start()啟動后,必須返回一個Task,而這個Task在整個狀態(tài)機流轉(zhuǎn)完畢后要變成完成狀態(tài),以便調(diào)用方在該Task上調(diào)用的ContinueWith得以繼續(xù)執(zhí)行,而就Task這個類而言,它是沒有提供這種方法(內(nèi)部有,但沒有對外暴露)來主動控制Task的狀態(tài)的,這個與JS中的Promise不同,JS里面用Reslove函數(shù)來主動控制Promise的狀態(tài),并導致在該Promise上面的Then鏈式調(diào)用得以繼續(xù)完成,而在C#里面怎么做呢?既然使用了狀態(tài)機來實現(xiàn)async/await,那么在轉(zhuǎn)換一個返回Task的函數(shù)時肯定會遇到,怎么處理?后面講。
  首先解決一下與Task類型緊密聯(lián)系這個問題。
  從狀態(tài)機中可以看到,主要使用到了Task中的ContinueWith這個函數(shù),它的語義是在任務完成后,執(zhí)行回調(diào)函數(shù),通過回調(diào)函數(shù)拿到結果,這個編程風格也叫做CPS(Continuation-Passing-Style, 續(xù)體傳遞風格),那么我們能不能把這個函數(shù)給抽象出來呢?語言開發(fā)者當然想到了,它被抽象成了一個Awaiter因此編譯器要求await的類型必須要有GetAwaiter方法,什么樣的類型才是Awaiter呢?編譯器規(guī)定主要實現(xiàn)了如下幾個方法的類型就是Awaiter:

  • 必須繼承INotifyCompletion接口,并實現(xiàn)其中的OnCompleted(Action continuation)方法
  • 必須包含IsCompleted屬性
  • 必須包含GetResult()方法

  第一點好理解,第二點的作用是熱路徑優(yōu)化,第三點以后講。我們再改造一下我們手動寫的狀態(tài)機。

public class TestAsyncStateMachine
{
    public int _state = 0;
    public void Start() => MoveNext();
    public void MoveNext()
    {
        switch(_state)
        {
            case 0:
                {
                    goto Step0;
                }
            case 1:
                    goto Step1;
            default:
                    Console.WriteLine("步驟3");
                    return;
        }
    Step0:
            Console.WriteLine("步驟1");
            _state = 1;
            TaskAwaiter taskAwaiter;
            taskAwaiter = WorkAsync().GetAwaiter();
            if (taskAwaiter.IsCompleted) goto Step1;
            taskAwaiter.OnCompleted(() => this.MoveNext());
            return;
    Step1:
            _state = -1;
            Console.WriteLine("步驟2");
            if (taskAwaiter.IsCompleted) MoveNext();
    }
}

  可以看到去掉了與Task中ContinueWith的耦合關系,并且如果任務已經(jīng)完成,則可以直接執(zhí)行下個任務,避免了無用的開銷。
  因此我們可以總結一下async/await:

  • async/await只是表示這個方法需要編譯器進行特殊處理,并不代表它本身一定是異步的。
  • Task類中的GetAwaiter主要是給編譯器用的。

  第一點我們可以用以下例子來證明,有興趣的朋友可以自己去驗證以下,以便加深理解。

//該類型包含GetAwaiter方法,且GetAwaiter()返回的類型包含三個必要條件
public class MyAwaiter : INotifyCompletion
{
    public void OnCompleted(Action continuation)
    {
        continuation();
    }

    public bool IsCompleted { get; }
    public void GetResult()
    
    public MyAwaiter GetAwaiter() => new MyAwaiter();
}

  一個測試函數(shù),注意必須返回void

public static async void AwaiterTest()
{
    await new MyAwaiter();
    Console.WriteLine("Done");
}

  可以看到這是完全同步進行的。

到此這篇關于C#異步編程由淺入深(二)之Async/Await的作用.的文章就介紹到這了,更多相關C#異步編程Async/Await內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 一文掌握C# ListView控件的用法和示例代碼

    一文掌握C# ListView控件的用法和示例代碼

    ListView控件提供了豐富的屬性和事件,可以用于實現(xiàn)各種各樣的表格視圖,包括帶有單元格編輯、排序和分組等功能,本文介紹了一些常見的?ListView?控件的用法和示例代碼,感興趣的朋友一起看看吧
    2024-02-02
  • C#操作配置文件app.config、web.config增刪改

    C#操作配置文件app.config、web.config增刪改

    這篇文章介紹了C#操作配置文件app.config、web.config增刪改的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • C#集合之不變集合的用法

    C#集合之不變集合的用法

    這篇文章介紹了C#集合之不變集合的用法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04
  • C#中TreeView節(jié)點的自定義繪制方法

    C#中TreeView節(jié)點的自定義繪制方法

    這篇文章主要介紹了C#中TreeView節(jié)點的自定義繪制方法,實例展示了TreeView節(jié)點的操作技巧,需要的朋友可以參考下
    2015-02-02
  • C#中值類型和引用類型解析

    C#中值類型和引用類型解析

    這篇文章主要為大家詳細介紹了C#中值類型和引用類型的相關資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • C#實現(xiàn)DataTable,List和Json轉(zhuǎn)換的方法

    C#實現(xiàn)DataTable,List和Json轉(zhuǎn)換的方法

    這篇文章主要介紹了C#實現(xiàn)DataTable,List和Json轉(zhuǎn)換的方法,結合實例形式分析了DataTable、list、DataReader、DataSet等轉(zhuǎn)換成JSON的相關實現(xiàn)技巧,需要的朋友可以參考下
    2016-08-08
  • C#中系統(tǒng)時間和UNIX時間戳互相轉(zhuǎn)換

    C#中系統(tǒng)時間和UNIX時間戳互相轉(zhuǎn)換

    本文主要介紹C#中系統(tǒng)時間和UNIX時間戳相互轉(zhuǎn)換的方法,大家可以直接拿去用,希望有用。
    2016-05-05
  • 如何獲取C#中方法的執(zhí)行時間以及其代碼注入詳解

    如何獲取C#中方法的執(zhí)行時間以及其代碼注入詳解

    這篇文章主要給大家介紹了關于如何獲取C#中方法的執(zhí)行時間以及其代碼注入的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起看看吧
    2018-11-11
  • 詳解C#設置Excel數(shù)據(jù)自適應行高、列寬的2種情況

    詳解C#設置Excel數(shù)據(jù)自適應行高、列寬的2種情況

    這篇文章主要介紹了C#設置Excel數(shù)據(jù)自適應行高、列寬的2種情況,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • Unity中的靜態(tài)批處理和動態(tài)批處理操作

    Unity中的靜態(tài)批處理和動態(tài)批處理操作

    這篇文章主要介紹了Unity中的靜態(tài)批處理和動態(tài)批處理操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04

最新評論

五台县| 锡林浩特市| 宽甸| 秦安县| 甘南县| 深州市| 东乡县| 长治县| 桐梓县| 柘荣县| 旅游| 鹤庆县| 无棣县| 石狮市| 金坛市| 卫辉市| 松江区| 静乐县| 嘉祥县| 哈尔滨市| 榆林市| 上犹县| 佳木斯市| 万宁市| 且末县| 扎囊县| 安平县| 南靖县| 利川市| 松潘县| 昌吉市| 广宗县| 齐齐哈尔市| 彭州市| 叶城县| 和林格尔县| 增城市| 金阳县| 尼玛县| 哈密市| 温泉县|