溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C#中async和await有什么用

發(fā)布時間:2021-07-01 13:46:35 來源:億速云 閱讀:882 作者:小新 欄目:開發(fā)技術

這篇文章將為大家詳細講解有關C#中async和await有什么用,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

    前言

    本文介紹async/Task。在學習該知識點過程中,一定要按照每一個示例,去寫代碼、執(zhí)行、輸出結果,自己嘗試分析思路。

    async

    微軟文檔:使用 async 修飾符可將方法、lambda 表達式或匿名方法指定為異步。

    使用 async 修飾的方法,稱為異步方法。

    例如:

    為了命名規(guī)范,使用 async 修飾的方法,需要在方法名稱后面加上 Async 。

    public async Task<int> TestAsync()  
    {  
        // . . . .  
    }
    Lambda :
    
    
            static void Main()
            {
                Thread thread = new Thread(async () =>
                {
                    await Task.Delay(0);
                });
            }
            public static async Task<int> TestAsync() => 666;

    await

    微軟文檔:await 運算符暫停對其所屬的 async 方法的求值,直到其操作數(shù)表示的異步操作完成。

    異步操作完成后,await 運算符將返回操作的結果(如果有)。

    好的,到此為止,async 和 await ,在官方文檔中的說明,就這么多。

    從以往知識推導

    這里我們不參考文檔和書籍的資料,不要看文檔和書籍中的示例,我們要一步步來從任務(Task)中的同步異步開始,慢慢摸索。去分析 async 和 await 兩個關鍵字給我們的異步編程帶來了什么樣的便利。

    創(chuàng)建異步任務

    場景:周六日放假了,可以打王者(一種游戲),但是昨天的衣服還沒有洗;于是用洗衣機洗衣服,清洗期間,開一局王者(一種游戲)。

    我們可以編寫一個方法如下:

    static void Main()
            {
                Console.WriteLine("準備洗衣服");
    
                // 創(chuàng)建一個洗衣服的任務
                Task<int> task = new Task<int>(() =>
                {
                    // 模擬洗衣服的時間
                    int time = new Random().Next(2, 6);
                    Thread.Sleep(TimeSpan.FromSeconds(time));
                    return time;
                });
    
                Console.WriteLine("開始洗衣服");
    
                // 讓洗衣機洗衣服
                task.Start();
    
                Console.WriteLine("我去打王者,讓洗衣機洗衣服");
                // 打王者
                Thread.Sleep(TimeSpan.FromSeconds(4));
                Console.WriteLine("打完王者了,衣服洗完了嘛?");
    
                Console.WriteLine(task.IsCompleted);
                if (task.IsCompleted)
                    Console.WriteLine("洗衣服花的時間:" + task.Result);
                else
                {
                    Console.WriteLine("在等洗衣機洗完衣服");
                    task.Wait();
                    Console.WriteLine("洗衣服花的時間:" + task.Result);
                }
                Console.WriteLine("洗完了,撈出衣服,曬衣服,繼續(xù)打王者去");
            }

    創(chuàng)建異步任務并返回Task

    上面的示例,雖然說,異步完成了一個任務,但是這樣,將代碼都放到 Main ,可讀性十分差,還要其它什么規(guī)范之類的,不允許我們寫這樣的垃圾代碼。于是我們將洗衣服這個任務,封裝到一個方法中,然后返回 Task 即可。

    在 Program 類中,加入如下一個方法,這個方法用于執(zhí)行異步任務,并且返回 Task 對象。

    /// <summary>
            /// 執(zhí)行一個任務
            /// </summary>
            /// <returns></returns>
            public static Task<int> TestAsync()
            {
                Task<int> task = new Task<int>(() =>
                {
                    // 模擬洗衣服的時間
                    int time = new Random().Next(2, 6);
                    Thread.Sleep(TimeSpan.FromSeconds(time));
                    return time;
                });
                task.Start();
                return task;
            }

    Main 方法中,改成

    static void Main()
            {
                Console.WriteLine("準備洗衣服");
    
                // 創(chuàng)建一個洗衣服的任務
                Task<int> task = TestAsync();
                ... ...

    但是,兩者差別還是不大。

    異步改同步

    我們創(chuàng)建了異步方法,去執(zhí)行一個洗衣服的任務;當打完游戲后,需要檢查任務是否完成,然后才能進行下一步操作,這時候就出現(xiàn)了 同步。為了保持同步和獲得執(zhí)行結果,我們使用了 .Wait() 、.Result 。

    這里我們嘗試將上面的操作轉為同步,并且獲得執(zhí)行結果。

    class Program
        {
            static void Main()
            {
                int time = Test();
                // ... ...
            }
    
            /// <summary>
            /// 執(zhí)行一個任務
            /// </summary>
            /// <returns></returns>
            public static int Test()
            {
                Task<int> task = new Task<int>(() =>
                {
                    // 模擬洗衣服的時間
                    int time = new Random().Next(2, 6);
                    Thread.Sleep(TimeSpan.FromSeconds(time));
                    return time;
                });
                task.Start();
                return task.Result;
            }
        }

    說說 await Task

    Task 和 Task<TResult> ,前者是一個沒有返回結果的任務,后者是有返回結果的任務。前面的文章中已經使用過大量的示例,這里我們使用 await ,去完成一些完全相同的功能。

    Task:

    public static void T1()
            {
                Task task = new Task(() => { });
                task.Wait();
            }
    public static async void T2()
            {
                Task task = new Task(() => {  });
                await task;
            }

    說明,await 可以讓程序等待任務完成。

    Task<TResult>:

       public void T3()
           {
               // 獲取 Task 任務對象,后面的邏輯過程可以弄成異步
               Task<int> task = TestAsync();
    
               // 任務是異步在執(zhí)行,我不理會他
               // 這里可以處理其它事情,處理完畢后,再獲取執(zhí)行結果
               // 這就是異步
    
               Console.WriteLine(task.Result);
           }
    public async void T4()
            {
                // 使用 await 關鍵字,代表等待執(zhí)行完成,同步
                int time = await TestAsync();
                Console.WriteLine(time);
            }

    說明:await 可以讓程序等待任務執(zhí)行完成,并且獲得執(zhí)行結果。

    看到沒有。。。await 關鍵字,作用是讓你等,是同步的,壓根不是直接讓你的任務變成異步后臺執(zhí)行的。

    那為啥提到 async 、await,都是說跟異步有關?不急,后面解釋。

    說說 async Task<TResult>

    async Task<TResult> 修飾一個方法,那么這個方法要返回 await Task<TResult> 的結果。

    C#中async和await有什么用

    兩種同步方式示例對比:

    public static int Test()
            {
                Task<int> task = new Task<int>(() =>
                {
                    // 模擬洗衣服的時間
                    int time = new Random().Next(2, 6);
                    Thread.Sleep(TimeSpan.FromSeconds(time));
                    return time;
                });
                task.Start();
                return task.Result;
            }
    public static async Task<int> TestAsync()
            {
                Task<int> task = new Task<int>(() =>
                {
                    // 模擬洗衣服的時間
                    int time = new Random().Next(2, 6);
                    Thread.Sleep(TimeSpan.FromSeconds(time));
                    return time;
                });
                task.Start();
                int time = await task;
                return time;
            }

    同步異步?

    問:async 和 await 不是跟異步方法有關嘛,為啥前面的示例使用了 await ,全部變成同步了?

    問:使用 async 和 await 的方法,執(zhí)行過程到底是同步還是異步?

    答:同步異步都行,要同步還是異步,全掌握在你的手上。

    • 你使用 await 去調用一個異步方法,其執(zhí)行過程就是同步。

    • 你獲取異步方法返回的 Task,就是異步。

    最近筆者收到一些提問,有些讀者,使用 async 和 await 去編寫業(yè)務,想著是異步,可以提升性能,實際結果還是同步,性能一點沒有提升。通過下面的示例,你會馬上理解應該怎么用。

    首先,在不使用 async 和 await 關鍵字的情況下,我們來編寫兩個方法,分別實現(xiàn)同步和異步的功能,兩個方法執(zhí)行的結果是一致的。

    /// <summary>
            /// 同步
            /// </summary>
            /// <returns></returns>
            public static int Test()
            {
                Task<int> task = new Task<int>(() =>
                {
                    return 666;
                });
                task.Start();
                return task.Result;
            }
            
            /// <summary>
            /// 異步
            /// </summary>
            /// <returns></returns>
            public static Task<int> TestAsync()
            {
                Task<int> task = new Task<int>(() =>
                {
                    return 666;
                });
                task.Start();
                return task;
            }

    能不能將兩個方法合并在一起呢?想同步就同步,想異步就異步,這樣就不需要寫兩個方法了!

    是可以的!通過 async 和 await 關鍵字,可以輕松實現(xiàn)!

    合并后,代碼如下:

    /// <summary>
            /// 可異步可同步
            /// </summary>
            /// <returns></returns>
            public static async Task<int> TestAsync()
            {
                Task<int> task = new Task<int>(() =>
                {
                    return 666;
                });
                task.Start();
                return await task;
            }

    合并后,我們又應該怎么在調用的時候,實現(xiàn)同步和異步呢?

    筆者這里給出兩個示例:

    // await 使得任務同步
            public async void T1()
            {
                // 使用 await 關鍵字,代表等待執(zhí)行完成,同步
                int time = await TestAsync();
                Console.WriteLine(time);
            }
    
            // 直接獲得返回的 Task,實現(xiàn)異步
            public void T2()
            {
                // 獲取 Task 任務對象,后面的邏輯過程可以弄成異步
                Task<int> task = TestAsync();
    
                // 任務是異步在執(zhí)行,我不理會他
                // 這里可以處理其它事情,處理完畢后,再獲取執(zhí)行結果
                // 這就是異步
    
                Console.WriteLine(task.Result);
            }

    至此,理解為什么使用了 async 和 await,執(zhí)行時還是同步了吧?

    Task封裝異步任務

    前面,我們都是使用了 new Task() 來創(chuàng)建任務,而且微軟官網大多使用 Task.Run() 來編寫 async 和 await 的示例。

    因此,我們可以修改前面的異步任務,改成:

    /// <summary>
            /// 可異步可同步
            /// </summary>
            /// <returns></returns>
            public static async Task<int> TestAsync()
            {
                return await Task.Run<int>(() =>
                {
                    return 666;
                });
            }

    關于跳到 await 變異步

    在百度學習異步的時候,往往會有作者說,進入異步方法后,同步執(zhí)行代碼,碰到 await 后就是異步執(zhí)行。

    當然還有多種說法。

    我們已經學習了這么多的任務(Task)知識,這一點十分容易解釋。

    因為使用了 async 和 await 關鍵字,代碼最深處,必定會出現(xiàn) Task 這個東西,Task 這個東西本來就是異步。碰到 await 出現(xiàn)異步,不是因為 await 的作用,而是因為最底層有個 Task。

    C#中async和await有什么用

    為什么出現(xiàn)一層層的 await

    這是相對于提供服務者來說。因為我要提供接口給你使用,因此底層出現(xiàn) async、await 后,我會繼續(xù)保留方法是異步的(async),然后繼續(xù)封裝,這樣就有多層的調用結構,例如上一小節(jié)的圖。

    但是如果來到了調用者這里,就不應該還是使用 async 、await 去編寫方法,而是應該按照實際情況同步或異步。

    關于“C#中async和await有什么用”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI