1、涉及內容html
async & await是C# 5.0引入的,控制檯輸出所使用的$符號(拼接字符串)是C# 6.0引入的,其功能相似於string.Format()方法。多線程
2、多線程、異步、同步之間的聯繫與區別異步
廚房案例:async
好比說你要炒5道菜ABCDE,可是隻有兩個爐子能夠用,即同時只能炒兩道菜。在這裏,爐子就是線程。ide
假如兩個爐子分別同時炒A和B,那剩下的CDE只能等A或B炒完了才能開始。這個等待的過程就是同步,咱們稱之爲阻塞,即這個時候你只能炒A和B這兩道菜。網站
假如你還有一臺咖啡機,在你炒A和B的時候順手把咖啡豆和水放到咖啡機裏打開開關,而後你就不用管它了。此時,就是新開了一個線程去煮咖啡,而煮咖啡atom
是由咖啡機自動完成的並不影響繼續炒菜,因此煮咖啡這個線程是異步的,咱們稱之爲非阻塞。url
當咖啡機叮的一聲通知你咖啡已經煮好了,你要去把咖啡拿出來加點糖或奶什麼的,這個拿咖啡的動做咱們稱之爲回調,這個是咖啡機線程完成以後通知你要去spa
作的動做。pwa
簡單來講:
會佔用你的時間讓你沒法去作其它事情的任務叫作同步任務(炒菜要專一不然會糊鍋)。
那些不須要佔用你的時間的任務叫作異步任務(咖啡機本身會把咖啡煮好,不須要你一直看着它)。
下面代碼演示不使用異步的狀況:
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。"); } }
運行結果以下:
下面代碼演示使用異步的狀況:
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。"); } }
運行結果以下:
三、async & await 結構
async & await結構可分紅三部分:
1)調用方法:該方法調用異步方法,而後在異步方法執行其任務的時候繼續執行;
2)異步方法:該方法異步執行工做,而後馬上返回到調用方法;
3)await表達式:用於異步方法內部,指出須要異步執行的任務。一個異步方法能夠包含多個await表達式(不存在 await 表達式的話IDE會發出警告)。
四、異步方法
異步方法:在執行完成前當即返回調用方法,在調用方法繼續執行的過程當中完成任務。
語法分析:
參考自: