天天看點

異步、多線程、Await/Async、Task

異步多線程曆險記、Await/Async、Task、Thread

異步多線程經常被拿來說事,網上文章也是多如牛毛,我也是停留在很菜的水準,痛下決心好好“惡補”一下這塊知識。

還是先放兩個官方文檔壓壓驚:使用 Async 和 Await 的異步程式設計    .NET 中的并行處理、并發和異步程式設計

耗時操作知道搞個Task.Run,不用等待結果就背景執行,Api直接傳回,多個任務就循環啟用Task。控制器方法加上async,調用加上await,别人這麼用也跟着,不造為毛。Thread最常用的是Sleep。。。就這樣。

多線程的前世今生就不具體介紹了,簡單粗暴的實操文章奉上:Thread、ThreadPool、Task、Parallel的基本用法、差別以及弊端

通過幾個小例子Get不明白的知識點,搞一個winform,啟動的同時再帶一個控制台,友善輸出對比,Program.cs需要加幾行代碼。大概放了這幾個按鈕,寫了幾個輸出和調用異步的方法(完整代碼在最後)。

異步、多線程、Await/Async、Task

這就不說了,睡3秒順序執行,有一點注意是文本框資訊是沒有即時更新的,winform正常情況下是主線程更新控件狀态的,因為主線程被阻塞了,是以無法重新整理UI,主線程釋放後才執行。

異步、多線程、Await/Async、Task
異步、多線程、Await/Async、Task

Over的時候可以發現更新資訊是由線程id為5的線程完成的,跨線程操作winform控件的方法交給委托,見紅框。

異步、多線程、Await/Async、Task
異步、多線程、Await/Async、Task
異步、多線程、Await/Async、Task

如果異步線程需要等待傳回值可以這樣寫更簡潔,方法上加上了async關鍵字,await等待線程執行,那麼問題來了,異步不就又變成同步了?意義何在呢?這也是實操前一直不明白的點,這個例子看不出效果,接着操作。

異步、多線程、Await/Async、Task
異步、多線程、Await/Async、Task

調用異步方法,自己本身也應該是異步的,如果沒有async關鍵字,就會報出警告,并且沒有async修飾的方法不能使用await關鍵字,這個例子隻是把異步方法MethodAsync拿出去了,為了示範下面的例子使用。

異步、多線程、Await/Async、Task
異步、多線程、Await/Async、Task

這裡調用異步方法MethodAsyncDeadlock,與MethodAsync的差別就是,把耗時函數的結果傳回了,由于主線程沒有等待異步調用傳回,又輸出了異步方法的結果,自然是拿不到傳回值,因為異步方法還沒有執行完成,是以這線程就“幹架”了,卡這了,死鎖。

異步、多線程、Await/Async、Task
異步、多線程、Await/Async、Task

死鎖大部分是代碼不規範造成的,代碼寫懵逼也是常有的事,解決也很簡單,await出馬,等異步方法完成傳回再繼續執行就OK了。

異步、多線程、Await/Async、Task
異步、多線程、Await/Async、Task

啟動方式直接看代碼,有一個小坑需要注意,就是多線程通路公共變量問題。

異步、多線程、Await/Async、Task

異步程式設計的意義何在這個哲學問題,換一個控制台例子更能說明問題。很簡單,一個控制台、一個類。從執行結果可以看出來,Main方法開始,到MethodAsync異步方法執行,開啟Task耗時函數之前都是線程1在幹活兒,耗時函數由另外一個線程4執行,開始之前線程1已已經傳回,并且輸出了Main End,這意味着剩下的不管是耗時函數,還是等待耗時函數完成之後的邏輯,都不在需要主線程等待完成,由别的線程搞定。winform解釋不來是因為異步完成之後還是交給了主線程UI去繼續執行了,是以線程id總是前後一緻。

異步、多線程、Await/Async、Task
異步、多線程、Await/Async、Task

實操分析完之後,就明白了之前忘記在哪看到的一句話了:異步能增加網站的吞吐量,但并不會讓網站變得更快。

1、提高網站的響應能力,也是async/await也常見于Web項目的原因。

2、可以用同步的寫法,完成異步操作,需要的時候啟動線程并行執行,提高運算或邏輯處理能力,又能等待控制順序,可以說賊爽。

參考了:C# 徹底搞懂async/await,也是言簡意赅的文章。

測試簽名

繼續閱讀