這幾天終於弄懂了async和await的模式,也搞明白了一直在內心面積壓着的許多問題,因此寫一篇博客來和你們分享一下。編程
關於異步機制我認爲只要記住的如下幾點,就能夠弄明白了:異步
1.我認爲async和awwait兩個修飾符中最關鍵的是await,async是因爲方法中包含await修飾符以後纔在方法定義中添加的,代表這個方法是一個異步方法。async
2.await只能用來修飾Task、Task<TResult>、ValueTask 或 ValueTask<TResult>這些類型的變量或者方法,他是一個分裂符,咱們須要記住的最關鍵一點是當程序進行到await的時候,方法會暫時返回,而await字符以後的內容會等await這一行返回後繼續執行。函數
3.在控制檯應用中,await以前的內容是一個線程執行,await以及awiat以後的內容會在另外一個線程中執行。學習
咱們在編程時不少時候其實都用錯了aiwat,這也致使我一開始學習的時候對await產生了很是多的疑問,以致於一直都沒有弄清楚,好比:spa
int bytesLoaded = await DownloadDocsMainPageAsync();
這個幾乎是咱們寫代碼時見到最多的用法了,在主方法中使用await 來作一些request的請求,當時就在想await不是異步嗎,但爲何還要在這裏等待這個輸出才進行下一步的執行呢?那麼異步是異步到哪裏了呢?其實這種使用方式並無體現出異步的特點,只是由於request中不少方法是異步方法而爲了獲取結果才這麼寫的,真正的使用方式實際上是下面這樣的:線程
Task<int> downloading = DownloadDocsMainPageAsync(); //省略代碼,這裏有一些處理方式// int bytesLoaded = await downloading;
異步是在咱們處理一件事的時候能夠同時進行着另外一件事,下圖說明了上面代碼在主方法中的調用邏輯:調試
另外我寫了一個異步的demo,這個方法裏面有兩個異步的例子,你們有興趣的話能夠在本地本身調試去感覺一下異步的實現方式和調用的順序,方便你們理解:code
//private static void Main(string[] args) //{ // //Console.WriteLine("111 balabala. My Thread ID is :" + Thread.CurrentThread.ManagedThreadId); // //var r = AsyncMethod(); // //Console.WriteLine(r); // //Console.WriteLine("222 balabala. My Thread ID is :" + Thread.CurrentThread.ManagedThreadId); // //Thread.Sleep(10000); //} public static async Task Main() { Task<int> downloading = DownloadDocsMainPageAsync(); Console.WriteLine($"{nameof(Main)}: Launched downloading."); Console.WriteLine("main1 " + Thread.CurrentThread.ManagedThreadId); int bytesLoaded = await downloading; Console.WriteLine("main2 " + Thread.CurrentThread.ManagedThreadId); Console.WriteLine($"{nameof(Main)}: Downloaded {bytesLoaded} bytes."); } private static async Task<int> DownloadDocsMainPageAsync() { Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: About to start downloading."); Console.WriteLine("sub1 " + Thread.CurrentThread.ManagedThreadId); var client = new HttpClient(); byte[] content = await client.GetByteArrayAsync("https://docs.microsoft.com/en-us/"); Console.WriteLine("sub2 " + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(5000); Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: Finished downloading."); return content.Length; } private async static Task<String> AsyncMethod() { var ResultFromTimeConsumingMethod = TimeConsumingMethod(); string Result = await ResultFromTimeConsumingMethod + " + AsyncMethod. My Thread ID is :" + Thread.CurrentThread.ManagedThreadId; Console.WriteLine(Result); Console.WriteLine(Thread.CurrentThread.ManagedThreadId); return Result; //返回值是Task的函數能夠不用return } //這個函數就是一個耗時函數,多是IO操做,也多是cpu密集型工做。 private static Task<string> TimeConsumingMethod() { var task = Task.Run(() => { Console.WriteLine("Helo I am TimeConsumingMethod. My Thread ID is :" + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(5000); Console.WriteLine("Helo I am TimeConsumingMethod after Sleep(5000). My Thread ID is :" + Thread.CurrentThread.ManagedThreadId); return "Hello I am TimeConsumingMethod"; }); return task; }
最後附上我參考的一些內容:blog
https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/operators/await
上面demo有一個被註釋了的main方法是我參考的另外一個大神的博客,正是讀了他的博客才讓我恍然大悟(雖然裏面的其餘敘述也不是很是準確),可是在理解async和await方面,這篇博客真正點醒了我,很惋惜我當時讀博客的時候並無收藏,後面也沒有找到博客地址,可是仍是要在這裏感謝他。