網站首頁 編程語言 正文
async和await
async
微軟文檔:使用?async
?修飾符可將方法、lambda 表達式或匿名方法指定為異步。
使用 async 修飾的方法,稱為異步方法。
例如:
為了命名規范,使用 async 修飾的方法,需要在方法名稱后面加上?Async
?。
public async Task<int> TestAsync() { // . . . . }
Lambda :
static void Main() { Thread thread = new Thread(async () => { await Task.Delay(0); }); } public static async Task<int> TestAsync() => 666;
await
微軟文檔:await
?運算符暫停對其所屬的?async
?方法的求值,直到其操作數表示的異步操作完成。
異步操作完成后,await
?運算符將返回操作的結果(如果有)。
好的,到此為止,async 和 await ,在官方文檔中的說明,就這么多。
從以往知識推導
這里,你會跟筆者從以往文章中學習到的知識,去推導,去理解 async 和 await 這兩個關鍵字是如何使用的,又應該怎么合理使用。
這里我們不參考文檔和書籍的資料,不要看文檔和書籍中的示例,我們要一步步來從任務(Task)中的同步異步開始,慢慢摸索。去分析 async 和 await 兩個關鍵字給我們的異步編程帶來了什么樣的便利。
創建異步任務
場景:周六日放假了,可以打王者(一種游戲),但是昨天的衣服還沒有洗;于是用洗衣機洗衣服,清洗期間,開一局王者(一種游戲)。
我們可以編寫一個方法如下:
static void Main() { Console.WriteLine("準備洗衣服"); // 創建一個洗衣服的任務 Task<int> task = new Task<int>(() => { // 模擬洗衣服的時間 int time = new Random().Next(2, 6); Thread.Sleep(TimeSpan.FromSeconds(time)); return time; }); Console.WriteLine("開始洗衣服"); // 讓洗衣機洗衣服 task.Start(); Console.WriteLine("我去打王者,讓洗衣機洗衣服"); // 打王者 Thread.Sleep(TimeSpan.FromSeconds(4)); Console.WriteLine("打完王者了,衣服洗完了嘛?"); Console.WriteLine(task.IsCompleted); if (task.IsCompleted) Console.WriteLine("洗衣服花的時間:" + task.Result); else { Console.WriteLine("在等洗衣機洗完衣服"); task.Wait(); Console.WriteLine("洗衣服花的時間:" + task.Result); } Console.WriteLine("洗完了,撈出衣服,曬衣服,繼續打王者去"); }
創建異步任務并返回Task
上面的示例,雖然說,異步完成了一個任務,但是這樣,將代碼都放到 Main ,可讀性十分差,還要其它什么規范之類的,不允許我們寫這樣的垃圾代碼。于是我們將洗衣服這個任務,封裝到一個方法中,然后返回 Task 即可。
在 Program 類中,加入如下一個方法,這個方法用于執行異步任務,并且返回 Task 對象。
/// <summary> /// 執行一個任務 /// </summary> /// <returns></returns> public static Task<int> TestAsync() { Task<int> task = new Task<int>(() => { // 模擬洗衣服的時間 int time = new Random().Next(2, 6); Thread.Sleep(TimeSpan.FromSeconds(time)); return time; }); task.Start(); return task; }
Main 方法中,改成
static void Main() { Console.WriteLine("準備洗衣服"); // 創建一個洗衣服的任務 Task<int> task = TestAsync(); ... ...
但是,兩者差別還是不大。
異步改同步
我們創建了異步方法,去執行一個洗衣服的任務;當打完游戲后,需要檢查任務是否完成,然后才能進行下一步操作,這時候就出現了?同步
。為了保持同步和獲得執行結果,我們使用了?.Wait()
?、.Result
?。
這里我們嘗試將上面的操作轉為同步,并且獲得執行結果。
class Program { static void Main() { int time = Test(); // ... ... } /// <summary> /// 執行一個任務 /// </summary> /// <returns></returns> public static int Test() { Task<int> task = new Task<int>(() => { // 模擬洗衣服的時間 int time = new Random().Next(2, 6); Thread.Sleep(TimeSpan.FromSeconds(time)); return time; }); task.Start(); return task.Result; } }
說說 await Task
Task
?和?Task<TResult>
?,前者是一個沒有返回結果的任務,后者是有返回結果的任務。前面的文章中已經使用過大量的示例,這里我們使用 await ,去完成一些完全相同的功能。
Task
:
public static void T1() { Task task = new Task(() => { }); task.Wait(); }
public static async void T2() { Task task = new Task(() => { }); await task; }
說明,await 可以讓程序等待任務完成。
Task<TResult>
:
public void T3() { // 獲取 Task 任務對象,后面的邏輯過程可以弄成異步 Task<int> task = TestAsync(); // 任務是異步在執行,我不理會他 // 這里可以處理其它事情,處理完畢后,再獲取執行結果 // 這就是異步 Console.WriteLine(task.Result); }
public async void T4() { // 使用 await 關鍵字,代表等待執行完成,同步 int time = await TestAsync(); Console.WriteLine(time); }
說明:await 可以讓程序等待任務執行完成,并且獲得執行結果。
看到沒有。。。await 關鍵字,作用是讓你等,是同步的,壓根不是直接讓你的任務變成異步后臺執行的。
那為啥提到 async 、await,都是說跟異步有關?不急,后面解釋。
說說?async Task<TResult>
async Task<TResult>
?修飾一個方法,那么這個方法要返回?await Task<TResult>
?的結果。
兩種同步方式示例對比:
public static int Test() { Task<int> task = new Task<int>(() => { // 模擬洗衣服的時間 int time = new Random().Next(2, 6); Thread.Sleep(TimeSpan.FromSeconds(time)); return time; }); task.Start(); return task.Result; }
public static async Task<int> TestAsync() { Task<int> task = new Task<int>(() => { // 模擬洗衣服的時間 int time = new Random().Next(2, 6); Thread.Sleep(TimeSpan.FromSeconds(time)); return time; }); task.Start(); int time = await task; return time; }
同步異步?
問:async 和 await 不是跟異步方法有關嘛,為啥前面的示例使用了 await ,全部變成同步了?
問:使用 async 和 await 的方法,執行過程到底是同步還是異步?
答:同步異步都行,要同步還是異步,全掌握在你的手上。
- 你使用 await 去調用一個異步方法,其執行過程就是同步。
- 你獲取異步方法返回的 Task,就是異步。
最近筆者收到一些提問,有些讀者,使用 async 和 await 去編寫業務,想著是異步,可以提升性能,實際結果還是同步,性能一點沒有提升。通過下面的示例,你會馬上理解應該怎么用。
首先,在不使用 async 和 await 關鍵字的情況下,我們來編寫兩個方法,分別實現同步和異步的功能,兩個方法執行的結果是一致的。
/// <summary> /// 同步 /// </summary> /// <returns></returns> public static int Test() { Task<int> task = new Task<int>(() => { return 666; }); task.Start(); return task.Result; } /// <summary> /// 異步 /// </summary> /// <returns></returns> public static Task<int> TestAsync() { Task<int> task = new Task<int>(() => { return 666; }); task.Start(); return task; }
能不能將兩個方法合并在一起呢?想同步就同步,想異步就異步,這樣就不需要寫兩個方法了!
是可以的!通過 async 和 await 關鍵字,可以輕松實現!
合并后,代碼如下:
/// <summary> /// 可異步可同步 /// </summary> /// <returns></returns> public static async Task<int> TestAsync() { Task<int> task = new Task<int>(() => { return 666; }); task.Start(); return await task; }
合并后,我們又應該怎么在調用的時候,實現同步和異步呢?
筆者這里給出兩個示例:
// await 使得任務同步 public async void T1() { // 使用 await 關鍵字,代表等待執行完成,同步 int time = await TestAsync(); Console.WriteLine(time); } // 直接獲得返回的 Task,實現異步 public void T2() { // 獲取 Task 任務對象,后面的邏輯過程可以弄成異步 Task<int> task = TestAsync(); // 任務是異步在執行,我不理會他 // 這里可以處理其它事情,處理完畢后,再獲取執行結果 // 這就是異步 Console.WriteLine(task.Result); }
至此,理解為什么使用了?async
?和?await
,執行時還是同步了吧?
Task封裝異步任務
前面,我們都是使用了?new Task()
?來創建任務,而且微軟官網大多使用?Task.Run()
?來編寫 async 和 await 的示例。
因此,我們可以修改前面的異步任務,改成:
/// <summary> /// 可異步可同步 /// </summary> /// <returns></returns> public static async Task<int> TestAsync() { return await Task.Run<int>(() => { return 666; }); }
關于跳到 await 變異步
在百度學習異步的時候,往往會有作者說,進入異步方法后,同步執行代碼,碰到 await 后就是異步執行。
當然還有多種說法。
我們已經學習了這么多的任務(Task)知識,這一點十分容易解釋。
因為使用了 async 和 await 關鍵字,代碼最深處,必定會出現 Task 這個東西,Task 這個東西本來就是異步。碰到 await 出現異步,不是因為 await 的作用,而是因為最底層有個 Task。
為什么出現一層層的 await
這是相對于提供服務者來說。因為我要提供接口給你使用,因此底層出現 async、await 后,我會繼續保留方法是異步的(async),然后繼續封裝,這樣就有多層的調用結構,例如上一小節的圖。
但是如果來到了調用者這里,就不應該還是使用 async 、await 去編寫方法,而是應該按照實際情況同步或異步。
原文鏈接:https://www.cnblogs.com/whuanle/p/12822705.html
相關推薦
- 2022-09-15 Go語言操作redis數據庫的方法_Golang
- 2022-04-22 使用elementui,upload組件,既要上傳文件,又要提交表單
- 2022-08-04 yolov5中head修改為decouple?head詳解_python
- 2022-10-13 解析批處理命令call和start_DOS/BAT
- 2022-07-30 Redis批量生成數據的實現_Redis
- 2022-03-04 前端添加把數組轉為String,后端查詢顯示把String拆分為數組
- 2023-06-17 C#中Stopwatch的使用及說明_C#教程
- 2022-05-13 修復Qt程序長時間運行控件停止刷新
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支