對於async和await的使用方式、作用效果不怎麼理解 ?沒關係,初步看這篇就夠了

學習中的苦與樂發表於2022-12-12

結論

同步還是非同步,區別如下:

  • 同步:你使用 await 修飾符去呼叫一個非同步(async)方法(是非同步方法,不過是阻塞式的,可簡單理解為同步);
  • 非同步:你獲取非同步方法返回的 Task,就是非同步(後文有程式碼示例);
  • 可以實現多工執行順序執行且不阻塞。

概述

async(C# 參考)

async 是“非同步”的簡寫,使用 async 修飾符可將方法、lambda 表示式匿名方法指定為非同步。

如果對方法或表示式使用此修飾符,則其稱為非同步方法 。

如下示例定義了一個名為 ExampleMethodAsync 的非同步方法:

public async Task<int> ExampleMethodAsync()
{
    //...
}

 

await(C# 參考)

await 運算子暫停對其所屬的 async 方法的求值,直到其運算元表示的非同步操作完成。

非同步操作完成後,await 運算子將返回操作的結果(如果有)。

當 await 運算子應用到表示已完成操作的運算元時,它將立即返回操作的結果,而不會暫停其所屬的方法。

 await 運算子不會阻止計算非同步方法的執行緒。

當 await 運算子暫停其所屬的非同步方法時,控制元件將返回到方法的呼叫方。

官網說的話是不是聽不明白?沒關係,你就理解為新增了await 修飾符後,必須要等呼叫返回後才能繼續執行下一步。

如下示例:

public async Task<int> ExampleMethodAsync()
{
    //...
    //這新增了await,執行到這裡需要等待MethodAwiat方法執行完成後才會往下繼續執行。
    int result = await MethodAwiat();
    //...

}
public async Task<int> MethodAwiat()
{
    //...
}

作用及基本用法

await和async可以簡化我們非同步程式設計,也可以讓我們以一種類似同步程式設計的方式來進行非同步程式設計。

另外當我們需要不阻塞主執行緒非同步執行,但又要有順序的執行相關程式碼的時候,await/async就可以排上用場。

基本用法如下示例:

        /// <summary>
        /// 可非同步可同步
        /// </summary>
        /// <returns></returns>
        public  async Task<string> TestAsync()
        {
            Thread.Sleep(3000);
            Task<string> task = new Task<string>(() =>
            {
                return "主程式返回後我還在執行資料:我是複雜的非同步執行的方法,不阻礙主程式執行。。。。。";
            });
            task.Start();
            return await task;
        }

        // await 使得任務同步
        public  async void T1()
        {
            // 使用 await 關鍵字,代表等待執行完成,同步
            string time = await TestAsync();
            Console.WriteLine(time);
            Console.WriteLine("執行完畢");
        }

        // 直接獲得返回的 Task,實現非同步
        public  void T2()
        {
            // 獲取 Task 任務物件,後面的邏輯過程可以弄成非同步
            Task<string> task = TestAsync();

            // 這裡可以處理其它事情,處理完畢後,再獲取執行結果
            Console.WriteLine("執行完畢");

            Console.WriteLine(task.Result);
        } 

 

實現多工順序執行且不阻塞

以微軟文件的做早餐的案例加以簡化來講解 【使用Async和Await可以實現多工順序執行且不阻塞】。

主線任務任務:倒橙汁 -> 烤麵包 -> 煎培根 -> 煎雞蛋 -> 倒咖啡。

1.同步執行

我們任務逐步順序執行如下,耗時:17064毫秒(17.064秒):

using Microsoft.International.Converters.TraditionalChineseToSimplifiedConverter;
using System;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {

        static void Main(string[] args)
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            PourOJ();
            PourCoffee();
            ToastBread();
            FryBacon();
            FryEggs();
            Console.WriteLine("早餐已經做完!");
            stopwatch.Stop();
            Console.WriteLine($"做早餐總計耗時:{stopwatch.ElapsedMilliseconds}");
            Console.ReadLine();

        }

        //倒橙汁
        private static void PourOJ()
        {
            Thread.Sleep(1000);
            Console.WriteLine("倒一杯橙汁");
        }

        //烤麵包
        private static void ToastBread()
        {
            Console.WriteLine("開始烤麵包");
            Thread.Sleep(3000);
            Console.WriteLine("烤麵包好了");

        }

        //煎培根
        private static void FryBacon()
        {
            Console.WriteLine("開始煎培根");
            Thread.Sleep(6000);
            Console.WriteLine("培根煎好了");
        }
        //煎雞蛋
        private static void FryEggs()
        {
            Console.WriteLine("開始煎雞蛋");
            Thread.Sleep(6000);
            Console.WriteLine("雞蛋好了");
        }

        //倒咖啡
        private static void PourCoffee()
        {
            Thread.Sleep(1000);
            Console.WriteLine("倒咖啡");
        }
    }
}

 

2.並行執行

如果此時我們每一項任務都有一個單獨的人去完成,將會縮短時間將近3倍(當然不能單純的用時間量化他),

如下,耗時6041毫秒(6.041秒):

using Microsoft.International.Converters.TraditionalChineseToSimplifiedConverter;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    class Program
    {

        static void Main(string[] args)
        {
            Test();
            Console.ReadLine();

        }

        private static void Test()
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            List<Task> tasks = new List<Task>() { PourOJ(), ToastBread(), FryBacon(), FryEggs(), PourCoffee() };
            Task.WhenAll(tasks).ContinueWith((t) =>
            {
                Console.WriteLine("早餐已經做完!");
                stopwatch.Stop();
                Console.WriteLine($"做早餐總計耗時:{stopwatch.ElapsedMilliseconds}");
            });
        }

        //倒橙汁
        private static async Task PourOJ()
        {
            await Task.Delay(1000);
            Console.WriteLine("倒一杯橙汁");
        }

        //烤麵包
        private static async Task ToastBread()
        {
            Console.WriteLine("開始烤麵包");
            await Task.Delay(3000);
            Console.WriteLine("烤麵包好了");

        }

        //煎培根
        private static async Task FryBacon()
        {
            Console.WriteLine("開始煎培根");
            await Task.Delay(6000);
            Console.WriteLine("培根煎好了");
        }
        //煎雞蛋
        private static async Task FryEggs()
        {
            Console.WriteLine("開始煎雞蛋");
            await Task.Delay(6000);
            Console.WriteLine("雞蛋好了");
        }

        //倒咖啡
        private static async Task PourCoffee()
        {
            await Task.Delay(1000);
            Console.WriteLine("倒咖啡");
        }
    }
}

 

3.並行且可指定順序執行

但是我們不可能每次做早餐都有那麼多人同時做,

需求變更:如果現在要求,先倒橙汁,然後倒咖啡,其餘的操作並行執行,應該如何操作呢?

只需將以上案例的主執行緒Test 方法修改如下,其他的不變,耗時8073毫秒(8.073秒):

private static async void Test()
        {
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            await PourOJ();             //倒橙汁
            await PourCoffee();         //然後倒咖啡
            List<Task> tasks = new List<Task>() { ToastBread(), FryBacon(), FryEggs() };//子任務List
            await Task.WhenAll(tasks);  //其餘的並行操作
            Console.WriteLine("早餐已經做完!");
            stopwatch.Stop();
            Console.WriteLine($"做早餐總計耗時:{stopwatch.ElapsedMilliseconds}");
        }

總結

我們發現,用好了async和await確實很節省時間。

大家可以想想怎麼優雅的在非同步裡面開多執行緒(多主執行緒多子執行緒)最節省時間。

參考文獻

 


 

喜歡就點贊加關注。

歡迎關注訂閱微信公眾號【熊澤有話說】,更多好玩易學知識等你來取
作者:熊澤-學習中的苦與樂
公眾號:熊澤有話說

QQ群:711838388
出處:https://www.cnblogs.com/xiongze520/p/16976940.html
您可以隨意轉載、摘錄,但請在文章內註明作者和原文連結。  

 

 

相關文章