網站首頁 編程語言 正文
一直對c#中async/await的用法模模糊糊,不太清晰,今天寫了一下Demo徹底明確一下async/await的用法,以免因為對其不了解而對后期的業務產生影響(比如事務導致的鎖表等等)。
1. 首先,async/await一般是成對出現才有意義。其意義在于可以等待異步操作完成后繼續順序執行,而不是異步操作還沒處理完成主線程就進行了下一步。
假設,我們現在要模擬簡單的下載場景,首先用戶點擊下載,那么就調用DownloadHandle方法(異步)進行下載,然后通知用戶下載完成。其使用async/await的區別如下:
(1)使用async/await 的情況:
internal class Program
{
static void Main(string[] args)
{
DownloadHandle();
Console.ReadLine();
}
/// <summary>
/// 正常使用async/await時,符合正常的業務邏輯:
/// 1. 通知用戶下載開始
/// 2. 異步下載
/// 3. 等待異步下載完成后給用戶提示下載完成
/// </summary>
public static async void DownloadHandle()
{
Console.WriteLine("下載開始!->主線程ID:" + Thread.CurrentThread.ManagedThreadId);
await Download();
Console.WriteLine("下載完成!->主線程ID:" + Thread.CurrentThread.ManagedThreadId);
}
/// <summary>
/// 下載
/// </summary>
/// <returns></returns>
public static Task Download()
{
return Task.Run(() =>
{
Console.WriteLine("下載線程ID:->" + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("10%");
Console.WriteLine("30%");
Console.WriteLine("50%");
Console.WriteLine("60%");
Console.WriteLine("80%");
Console.WriteLine("99%");
Console.WriteLine("100%");
});
}
}
結果如下:
可以看到,即時下載使用了異步(線程ID不同也表明了當前使用了異步),業務邏輯最終還是按照我們的需求,按順序正序執行了。
(2)不使用async/await的情況:
internal class Program
{
static void Main(string[] args)
{
DownloadHandle();
Console.ReadLine();
}
/// <summary>
/// 不適用async/await時,則代碼執行順序時混亂的,不符合業務邏輯:
/// 1. 通知用戶下載開始
/// 2. 提示下載完成
/// 3. 開始下載
/// </summary>
public static void DownloadHandle()
{
Console.WriteLine("下載開始!->主線程ID:" + Thread.CurrentThread.ManagedThreadId);
Download();
Console.WriteLine("下載完成!->主線程ID:" + Thread.CurrentThread.ManagedThreadId);
}
/// <summary>
/// 下載
/// </summary>
/// <returns></returns>
public static Task Download()
{
return Task.Run(() =>
{
Console.WriteLine("下載線程ID:->" + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("10%");
Console.WriteLine("30%");
Console.WriteLine("50%");
Console.WriteLine("60%");
Console.WriteLine("80%");
Console.WriteLine("99%");
Console.WriteLine("100%");
});
}
}
結果如下:
可以看到,代碼執行順序混亂了,“下載完成” 跑到了 “下載線程ID” 前面去了,完全沒有按照我們預期的順序執行。
2. 如果可以await的方法不進行await,那將會怎樣呢?
(1)如果被調用的異步方法內部使用了Task.Run,那結果可參考我們1中進行講述的結果。開發者可根據實際需要來進行調用,如果異步方法的調用結果與其上下文邏輯沒有嚴格的執行要求,則可以不進行await(比如記錄日志等等)。反之,則需要加await。
(2)如果被調用的異步方法內部只是返回了Task.CompletedTask,即時使用了await/async實際上還是等于同步執行,如下圖。
internal class Program
{
static void Main(string[] args)
{
DownloadHandle();
Console.ReadLine();
}
/// <summary>
/// 模擬下載
/// </summary>
public static async void DownloadHandle()
{
Console.WriteLine("下載開始!->主線程ID:" + Thread.CurrentThread.ManagedThreadId);
await Download();
Console.WriteLine("下載完成!->主線程ID:" + Thread.CurrentThread.ManagedThreadId);
}
/// <summary>
/// 下載
/// </summary>
/// <returns></returns>
public static Task Download()
{
Console.WriteLine("下載線程ID:->" + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("10%");
Console.WriteLine("30%");
Console.WriteLine("50%");
Console.WriteLine("60%");
Console.WriteLine("80%");
Console.WriteLine("99%");
Console.WriteLine("100%");
return Task.CompletedTask;
}
結果如圖:
可以看到,即使DonwloadHandle方法使用了await/async,還是進行了同步執行,并沒有異步效果(可從所有線程ID相同看出)
3.小技巧: 異步方法的返回值類型一般都是Task或者Task<T>類型的,當返回值為Task時(即方法的返回值類型為void),我們可以直接return Task.Run(()=>{})(以下第一段代碼),而不必awaitTask.Run(()=>{})(以下第二段代碼),這樣也可從一定程度上提高代碼執行效率。
/// <summary>
/// 下載
/// </summary>
/// <returns></returns>
public static Task Download()
{
return Task.Run(() =>
{
Console.WriteLine("下載線程ID:->" + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("10%");
Console.WriteLine("30%");
Console.WriteLine("50%");
Console.WriteLine("60%");
Console.WriteLine("80%");
Console.WriteLine("99%");
Console.WriteLine("100%");
});
}
/// <summary>
/// 下載
/// </summary>
/// <returns></returns>
public static async Task Download()
{
await Task.Run(() =>
{
Console.WriteLine("下載線程ID:->" + Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("10%");
Console.WriteLine("30%");
Console.WriteLine("50%");
Console.WriteLine("60%");
Console.WriteLine("80%");
Console.WriteLine("99%");
Console.WriteLine("100%");
});
}
原文鏈接:https://www.cnblogs.com/w821759016/p/17101852.html
相關推薦
- 2023-05-05 Python?pip更新的兩種方式詳解_python
- 2022-11-19 ubuntu desktop 開啟root賬戶
- 2022-07-28 Golang配置管理庫?Viper的教程詳解_Golang
- 2022-07-08 C#中Lambda表達式的用法_C#教程
- 2022-06-08 freertos實時操作系統臨界段保護開關中斷及進入退出_操作系統
- 2022-09-12 python中的集合及集合常用的使用方法_python
- 2022-06-26 python如何利用matplotlib繪制并列雙柱狀圖并標注數值_python
- 2022-04-11 【Android,kotlin】寫倒計時CountDown的正確姿勢
- 最近更新
-
- 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同步修改后的遠程分支