C#線程學習筆記八:async & await入門一


    一、涉及內容

    async & await是C# 5.0引入的,控制台輸出所使用的$符號(拼接字符串)是C# 6.0引入的,其功能類似於string.Format()方法。

    二、多線程、異步、同步之間的聯系與區別

    廚房案例:

    比如說你要炒5道菜ABCDE,但是只有兩個爐子可以用,即同時只能炒兩道菜。在這里,爐子就是線程。

    假如兩個爐子分別同時炒A和B,那剩下的CDE只能等A或B炒完了才能開始。這個等待的過程就是同步,我們稱之為阻塞,即這個時候你只能炒A和B這兩道菜。

    假如你還有一台咖啡機,在你炒A和B的時候順手把咖啡豆和水放到咖啡機里打開開關,然后你就不用管它了。此時,就是新開了一個線程去煮咖啡,而煮咖啡

是由咖啡機自動完成的並不影響繼續炒菜,所以煮咖啡這個線程是異步的,我們稱之為非阻塞

    當咖啡機叮的一聲通知你咖啡已經煮好了,你要去把咖啡拿出來加點糖或奶什么的,這個拿咖啡的動作我們稱之為回調,這個是咖啡機線程完成之后通知你要去

做的動作。

    簡單來說:

    會占用你的時間讓你無法去做其它事情的任務叫做同步任務(炒菜要專注否則會糊鍋)。

    那些不需要占用你的時間的任務叫做異步任務(咖啡機自己會把咖啡煮好,不需要你一直看着它)。

    下面代碼演示不使用異步的情況:

    class Program
    {
        //創建計時器
        private static readonly Stopwatch stopwatch = new Stopwatch();

        static void Main(string[] args)
        {
            #region async & await入門一之不使用異步
            //啟動計時器
            stopwatch.Start();
            //URL地址
            const string url1 = "http://www.cnblogs.com/";
            const string url2 = "http://www.cnblogs.com/atomy/";
            //異步下載某網站內容,並統計字符的個數。
            var result1 = CountCharacters("url1", url1);
            var result2 = CountCharacters("url2", url2);
            //主要是通過拼接字符串達到耗時操作
            for (var i = 0; i < 3; i++)
            {
                ExtraOperation(i + 1);
            }
            //控制台輸出
            Console.WriteLine($"{url1} 的字符個數:{result1}");
            Console.WriteLine($"{url2} 的字符個數:{result2}");
            Console.WriteLine($"總耗時{stopwatch.ElapsedMilliseconds}ms。");
            Console.Read();
            #endregion
        }

        /// <summary>
        /// 統計字符個數
        /// </summary>
        /// <param name="id"></param>
        /// <param name="address"></param>
        /// <returns></returns>
        private static int CountCharacters(string name, string address)
        {
            var wc = new WebClient();
            Console.WriteLine($"{name}開始調用,歷時{stopwatch.ElapsedMilliseconds}ms,線程id={Thread.CurrentThread.ManagedThreadId}。");

            var result = wc.DownloadString(address);
            Console.WriteLine($"{name}調用完成,歷時{stopwatch.ElapsedMilliseconds}ms,線程id={Thread.CurrentThread.ManagedThreadId}。");

            return result.Length;
        }

        /// <summary>
        /// 額外操作
        /// </summary>
        /// <param name="id"></param>
        private static void ExtraOperation(int id)
        {
            //這里是通過拼接字符串進行一些相對耗時的操作
            var s = "";
            for (var i = 0; i < 6000; i++)
            {
                s += i;
            }
            Console.WriteLine($"第{id}次ExtraOperation執行完成,歷時:{stopwatch.ElapsedMilliseconds}ms。");
        }
    }
View Code

    運行結果如下:

    下面代碼演示使用異步的情況:

    class Program
    {
        //創建計時器
        private static readonly Stopwatch stopwatch = new Stopwatch();

        static void Main(string[] args)
        {
            #region async & await入門一之使用異步
            //啟動計時器
            stopwatch.Start();
            //URL地址
            const string url1 = "http://www.cnblogs.com/";
            const string url2 = "http://www.cnblogs.com/atomy/";
            //異步下載某網站內容,並統計字符的個數。
            Task<int> t1 = CountCharactersAsync("url1", url1);
            Task<int> t2 = CountCharactersAsync("url2", url2);
            //主要是通過拼接字符串達到耗時操作
            for (var i = 0; i < 3; i++)
            {
                ExtraOperation(i + 1);
            }
            //控制台輸出
            Console.WriteLine($"{url1} 的字符個數:{t1.Result}");
            Console.WriteLine($"{url2} 的字符個數:{t2.Result}");
            Console.WriteLine($"總耗時{stopwatch.ElapsedMilliseconds}ms。");
            Console.Read();
            #endregion
        }

        /// <summary>
        /// 統計字符個數
        /// </summary>
        /// <param name="id"></param>
        /// <param name="address"></param>
        /// <returns></returns>
        private static async Task<int> CountCharactersAsync(string name, string address)
        {
            var wc = new WebClient();
            Console.WriteLine($"{name}開始調用,歷時{stopwatch.ElapsedMilliseconds}ms,線程id={Thread.CurrentThread.ManagedThreadId}。");

            var result =await wc.DownloadStringTaskAsync(address);
            Console.WriteLine($"{name}調用完成,歷時{stopwatch.ElapsedMilliseconds}ms,線程id={Thread.CurrentThread.ManagedThreadId}。");

            return result.Length;
        }

        /// <summary>
        /// 額外操作
        /// </summary>
        /// <param name="id"></param>
        private static void ExtraOperation(int id)
        {
            //這里是通過拼接字符串進行一些相對耗時的操作
            var s = "";
            for (var i = 0; i < 6000; i++)
            {
                s += i;
            }
            Console.WriteLine($"第{id}次ExtraOperation執行完成,歷時:{stopwatch.ElapsedMilliseconds}ms。");
        }
    }
View Code

    運行結果如下:

    三、async & await 結構

    async & await結構可分成三部分:

    1)調用方法:該方法調用異步方法,然后在異步方法執行其任務的時候繼續執行。

    2)異步方法:該方法異步執行工作,然后立刻返回到調用方法。

    3)await表達式:用於異步方法內部,指出需要異步執行的任務。

    四、異步方法

    異步方法:在執行完成前立即返回調用方法,在調用方法繼續執行的過程中完成任務。

    語法分析:

    1)關鍵字:方法頭返回類型前使用async關鍵字,它是一個上下文關鍵字。
    2)要求:需有await表達式(可多個)方可進行異步操作,否則視為普通方法進行同步操作。
    3)返回類型:只能返回3種類型(void、Task和Task<T>)。Task和Task<T>標識返回的對象會在將來完成工作,表示調用方法和異步方法可以繼續執行。
    4)參數:數量不限,但不能使用out和ref關鍵字。
    5)命名約定:方法后綴名應以Async結尾。
    6)其它:匿名方法和 Lambda 表達式也可以作為異步對象。

    參考自:

    https://www.cnblogs.com/woxihuadabai/p/8042652.html

    https://www.cnblogs.com/liqingwen/p/5831951.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM