這幾天終於弄懂了async和await的模式,也搞明白了一直在心裡面積壓著的許多問題,所以寫一篇博客來和大家分享一下。 關於非同步機制我認為只要記住的以下幾點,就可以弄明白了: 1.我認為async和awwait兩個修飾符中最關鍵的是await,async是由於方法中包含await修飾符之後才在方法定 ...
這幾天終於弄懂了async和await的模式,也搞明白了一直在心裡面積壓著的許多問題,所以寫一篇博客來和大家分享一下。
關於非同步機制我認為只要記住的以下幾點,就可以弄明白了:
1.我認為async和awwait兩個修飾符中最關鍵的是await,async是由於方法中包含await修飾符之後才在方法定義中添加的,表明這個方法是一個非同步方法。
2.await只能用來修飾Task、Task<TResult>、ValueTask 或 ValueTask<TResult>這些類型的變數或者方法,他是一個分裂符,我們需要記住的最關鍵一點是當程式進行到await的時候,方法會暫時返回,而await字元之後的內容會等await這一行返回後繼續執行。
3.在控制台應用中,await之前的內容是一個線程執行,await以及awiat之後的內容會在另一個線程中執行。
我們在編程時很多時候其實都用錯了aiwat,這也導致我一開始學習的時候對await產生了非常多的疑問,以至於一直都沒有弄清楚,比如:
int bytesLoaded = await DownloadDocsMainPageAsync();
這個幾乎是我們寫代碼時見到最多的用法了,在主方法中使用await 來做一些request的請求,當時就在想await不是非同步嗎,但為什麼還要在這裡等待這個輸出才進行下一步的執行呢?那麼非同步是非同步到哪裡了呢?其實這種使用方式並沒有體現出非同步的特色,只是因為request中很多方法是非同步方法而為了獲取結果才這麼寫的,真正的使用方式其實是下麵這樣的:
Task<int> downloading = DownloadDocsMainPageAsync(); //省略代碼,這裡有一些處理方式// int bytesLoaded = await downloading;
非同步是在我們處理一件事的時候可以同時進行著另一件事,下圖說明瞭上面代碼在主方法中的調用邏輯:
另外我寫了一個非同步的demo,這個方法裡面有兩個非同步的例子,大家有興趣的話可以在本地自己調試去感受一下非同步的實現方式和調用的順序,方便大家理解:
//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; }
最後附上我參考的一些內容:
https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/operators/await
上面demo有一個被註釋了的main方法是我參考的另一個大神的博客,正是讀了他的博客才讓我恍然大悟(雖然裡面的其他敘述也不是非常準確),但是在理解async和await方面,這篇博客真正點醒了我,很可惜我當時讀博客的時候並沒有收藏,後面也沒有找到博客地址,但是還是要在這裡感謝他。