C# 異步詳解

C# 異步編程詳解

一、異步編程基礎概念

1. 同步 vs 異步

  • ??同步(Synchronous)??:任務按順序執行,前一個任務完成后才會執行下一個
  • ??異步(Asynchronous)??:任務可以非阻塞地啟動,主線程可以繼續執行其他操作

2. 異步編程的優勢

  • 提高應用程序響應能力(特別是UI應用)
  • 更好地利用系統資源
  • 避免線程阻塞
  • 提高吞吐量

二、C#異步編程模型

1. async/await關鍵字

public async Task<string> GetDataAsync()
{// 模擬耗時操作await Task.Delay(1000);return "Data loaded";
}// 使用
var data = await GetDataAsync();
Console.WriteLine(data);

??關鍵點??:

  • async修飾方法,表示該方法包含異步操作
  • await關鍵字用于等待異步操作完成
  • 異步方法返回TaskTask<T>

2. Task和Task

// 返回void的異步方法(僅用于事件處理)
public async void HandleButtonClick()
{await SomeAsyncOperation();
}// 返回Task的異步方法
public async Task ProcessDataAsync()
{await File.ReadAllTextAsync("data.txt");
}// 返回Task<T>的異步方法
public async Task<int> CalculateSumAsync(IEnumerable<int> numbers)
{return await Task.Run(() => numbers.Sum());
}

??Task狀態??:

  • Created:已創建但未啟動
  • WaitingForActivation:等待激活
  • WaitingToRun:等待運行
  • Running:正在運行
  • RanToCompletion:已完成
  • Canceled:已取消
  • Faulted:出錯

三、異步方法實現方式

1. 基于I/O的異步操作

// 文件I/O
public async Task ReadFileAsync(string path)
{using (var reader = File.OpenText(path)){var content = await reader.ReadToEndAsync();Console.WriteLine(content);}
}// 網絡I/O
public async Task DownloadDataAsync(string url)
{using (var client = new HttpClient()){var response = await client.GetStringAsync(url);Console.WriteLine(response);}
}

2. 基于CPU的異步操作

// 使用Task.Run將CPU密集型工作轉移到線程池
public async Task ProcessDataAsync(IEnumerable<int> data)
{var result = await Task.Run(() =>{// CPU密集型計算return data.Sum(x => x * x);});Console.WriteLine($"Sum: {result}");
}

??注意??:對于真正的并行計算,考慮使用Parallel.For或PLINQ

3. 組合多個異步操作

// 等待多個任務完成
public async Task ProcessMultipleAsync()
{var task1 = GetDataAsync();var task2 = GetOtherDataAsync();// 等待所有完成await Task.WhenAll(task1, task2);Console.WriteLine($"Data1: {task1.Result}, Data2: {task2.Result}");
}// 等待任意一個完成
public async Task ProcessAnyAsync()
{var task1 = GetDataAsync();var task2 = GetOtherDataAsync();var completedTask = await Task.WhenAny(task1, task2);Console.WriteLine($"Completed: {completedTask == task1 ? "Task1" : "Task2"}");
}

四、異步編程最佳實踐

1. 避免async void

// 不推薦 - 無法捕獲異常
public async void DangerousMethod()
{throw new Exception("Oops!");
}// 推薦 - 可以await或等待
public async Task SafeMethodAsync()
{await Task.Delay(100);throw new Exception("Oops!");
}

??例外??:事件處理程序可以使用async void

2. 異常處理

public async Task HandleExceptionsAsync()
{try{await SomeAsyncOperation();}catch (Exception ex){// 處理異常Console.WriteLine($"Error: {ex.Message}");}
}// 多個任務的異常處理
public async Task HandleMultipleExceptionsAsync()
{try{await Task.WhenAll(Operation1(),Operation2(),Operation3());}catch (AggregateException ae){foreach (var ex in ae.InnerExceptions){Console.WriteLine($"Error: {ex.Message}");}}
}

3. 取消異步操作

// 使用CancellationToken
public async Task LongRunningOperationAsync(CancellationToken token)
{for (int i = 0; i < 100; i++){token.ThrowIfCancellationRequested();await Task.Delay(100, token);Console.WriteLine($"Step {i}");}
}// 使用示例
var cts = new CancellationTokenSource();
try
{await LongRunningOperationAsync(cts.Token);
}
catch (OperationCanceledException)
{Console.WriteLine("Operation was canceled");
}// 取消操作
cts.Cancel();

4. 異步方法設計原則

  1. ??返回Task而非void??(除非是事件處理程序)
  2. ??避免在異步方法中使用Result或Wait()??(可能導致死鎖)
  3. ??保持異步方法鏈??(避免混合同步和異步代碼)
  4. ??考慮異步方法的粒度??(不要過度拆分)

五、異步與并行編程

1. 異步 vs 并行

特性異步編程并行編程
目標非阻塞執行同時執行多個任務
線程使用通常不創建新線程使用多個線程
適用場景I/O密集型操作CPU密集型操作
關鍵字async/awaitParallel.For/ForEach

2. 混合使用示例

public async Task ProcessDataAsync(IEnumerable<Data> data)
{// 并行處理數據項var processedData = data.AsParallel().Select(d => ProcessItem(d)).ToList();// 異步保存結果await SaveResultsAsync(processedData);
}private Data ProcessItem(Data d)
{// CPU密集型處理return new Data { /* ... */ };
}private async Task SaveResultsAsync(IEnumerable<Data> data)
{// 異步保存到數據庫await _dbContext.BulkInsertAsync(data);
}

六、異步編程中的常見問題

1. 死鎖問題

??錯誤示例??:

public async Task DeadlockExample()
{await Task.Run(async () =>{// 在UI線程上調用Wait()會導致死鎖await SomeAsyncOperation().ConfigureAwait(false); // 解決方案}).Wait(); // 阻塞調用
}

??解決方案??:

  • 使用ConfigureAwait(false)(非UI上下文)
  • 避免在異步方法中調用.Result.Wait()
  • 使用await而不是Task.Run包裝異步操作

2. 上下文保留問題

// 默認情況下,await會捕獲當前上下文(如UI線程)
public async Task UpdateUIAsync()
{var data = await GetDataAsync();// 自動回到UI線程textBox.Text = data;
}// 如果不需要回到原始上下文
public async Task ProcessInBackgroundAsync()
{var data = await GetDataAsync().ConfigureAwait(false);// 不會回到原始上下文ProcessData(data);
}

3. 性能優化

??避免過度異步化??:

// 不必要的異步包裝
public async Task UnnecessaryAsync()
{await Task.Run(() => {// 同步操作Thread.Sleep(1000);});
}

??正確做法??:

  • 只對真正的I/O操作使用異步
  • 對CPU密集型操作考慮并行處理
  • 避免在熱路徑上使用異步(如游戲循環)

七、高級異步模式

1. 異步流(IAsyncEnumerable)

// 生成異步流
public async IAsyncEnumerable<int> GenerateNumbersAsync(int count)
{for (int i = 0; i < count; i++){await Task.Delay(100); // 模擬異步操作yield return i;}
}// 使用異步流
await foreach (var number in GenerateNumbersAsync(10))
{Console.WriteLine(number);
}

2. 異步鎖

private readonly SemaphoreSlim _semaphore = new(1, 1);public async Task ProtectedOperationAsync()
{await _semaphore.WaitAsync();try{// 受保護的代碼}finally{_semaphore.Release();}
}

3. 異步工廠模式

public interface IAsyncFactory<T>
{Task<T> CreateAsync();
}public class AsyncDataFactory : IAsyncFactory<Data>
{public async Task<Data> CreateAsync(){await Task.Delay(100); // 模擬異步初始化return new Data();}
}

八、異步測試

1. 單元測試異步方法

[Fact]
public async Task TestAsyncMethod()
{// Arrangevar service = new MyService();// Actvar result = await service.GetAsync();// AssertAssert.NotNull(result);
}// 使用Moq測試異步方法
[Fact]
public async Task TestWithMock()
{var mock = new Mock<IRepository>();mock.Setup(r => r.GetDataAsync()).ReturnsAsync(new Data { Id = 1 });var service = new MyService(mock.Object);var result = await service.GetData();Assert.Equal(1, result.Id);
}

2. 測試異步代碼中的異常

[Fact]
public async Task TestException()
{// Arrangevar service = new FaultyService();// Act & Assertawait Assert.ThrowsAsync<InvalidOperationException>(() => service.FaultyOperationAsync());
}

九、異步性能監控

1. 使用DiagnosticSource

// 在異步方法中添加診斷事件
private static readonly DiagnosticSource _diagnosticSource = new DiagnosticListener("MyAsyncComponent");public async Task ProcessAsync()
{if (_diagnosticSource.IsEnabled("StartProcess")){_diagnosticSource.Write("StartProcess", new { Timestamp = DateTime.UtcNow });}await Task.Delay(100);if (_diagnosticSource.IsEnabled("EndProcess")){_diagnosticSource.Write("EndProcess", new { Duration = 100 });}
}

2. 使用AsyncLocal跟蹤上下文

private static readonly AsyncLocal<string> _context = new();public async Task OperationWithContext()
{_context.Value = "OperationStarted";await Task.Delay(100);Console.WriteLine(_context.Value); // 仍然可以訪問
}

十、異步編程的未來發展

1. C#中的新特性

  • ??C# 8.0??:IAsyncEnumerable
  • ??C# 9.0??:異步流改進
  • ??C# 10.0??:更高效的異步方法生成

2. .NET中的改進

  • ??.NET Core 3.0+??:更好的異步IO性能
  • ??.NET 5+??:統一的異步API
  • ??.NET 6+??:更智能的異步調度器

十一、最佳實踐總結

  1. ??優先使用async/await??而非ContinueWith或Task.Result
  2. ??在UI應用中??,確保異步操作回到UI線程(使用ConfigureAwait(false)謹慎)
  3. ??避免混合同步和異步代碼??(如Wait()和Result)
  4. ??為長時間運行的操作??使用CancellationToken
  5. ??考慮異步流??處理連續數據(如日志、傳感器數據)
  6. ??測試異步代碼??時使用AsyncTestMethods
  7. ??監控異步性能??以識別瓶頸
  8. ??保持異步方法鏈??避免混合同步/異步調用

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/903808.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/903808.shtml
英文地址,請注明出處:http://en.pswp.cn/news/903808.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++ 之 【模擬實現 list(節點、迭代器、常見接口)】(將三個模板放在同一個命名空間就實現 list 啦)

1.前提準備 (1) list 的底層結構一般是帶頭雙向循環鏈表 (1)為避免命名沖突&#xff0c;需要創建一個命名空間來存放模擬實現的 list (2)下面模擬實現list時&#xff0c;聲明和定義不分離(具體原因后續講解) 2.完整實現 2.1 鏈表節點 template<class T>//節點寫成類模板…

解決Win10虛擬機“網絡連接不上”,“Ethernet0 網絡電纜被拔出”的問題

一、情景引入 今天用Win10虛擬機打開瀏覽器發現&#xff1a; 很奇怪&#xff0c;平常都沒有這個問題。 二、檢查網絡狀態 點擊更改適配器選項&#xff0c;發現如下&#xff1a; 三、解決問題 打開任務管理器&#xff0c;點擊服務&#xff0c;搜索欄搜索&#xff1a;VM …

2025藍橋杯省賽網絡安全組wp

文章目錄 黑客密室逃脫ezEvtxflowzipEnigma星際xml解析器EBC-TrainAES-CBC 黑客密室逃脫 提示猜文件名&#xff0c;猜幾個常見的&#xff0c;app.py讀到源碼 這里也是腦抽了一下&#xff0c;把密鑰看成1236了。。。卡了五分鐘左右&#xff0c;解出來的時候已經降到300多分了&a…

算法查找目錄

1. 基礎數據結構 數組與鏈表 動態數組 實現與自動擴容機制均攤分析ArrayList/Vector實現 單向鏈表 基本操作(插入、刪除、查找)鏈表反轉環檢測(Floyd判圈算法) 雙向鏈表 插入刪除操作優化雙向遍歷優勢邊界情況處理 循環鏈表 約瑟夫環問題單向循環鏈表雙向循環鏈表 跳表 基本原…

Windows11 管理員用戶下無權限操作的解決方法

問題 Program Files 目錄下無權限進行寫入操作。 Windows 各種功能因權限不足無法訪問。 啟動某些應用程序時&#xff0c;可能會遇到 用戶賬戶控制 (UAC, User Account Control) 彈窗提示&#xff0c;要求確認是否允許該程序對設備進行更改。 等等問題 解決方法 運行 p…

.NET中,const和readonly區別

在.NET中&#xff0c;const和readonly都用于定義不可變的值&#xff0c;但它們在行為和使用場景上有顯著區別。以下是兩者的詳細對比&#xff1a; 初始化時機 ? const ? 編譯時常量&#xff0c;必須在聲明時賦值。 ? 值在編譯時確定&#xff0c;并被直接嵌入到IL代碼中&…

郵件分類特征維度實驗分析

活動發起人小虛竹 想對你說&#xff1a; 這是一個以寫作博客為目的的創作活動&#xff0c;旨在鼓勵大學生博主們挖掘自己的創作潛能&#xff0c;展現自己的寫作才華。如果你是一位熱愛寫作的、想要展現自己創作才華的小伙伴&#xff0c;那么&#xff0c;快來參加吧&#xff01…

數字智慧方案6158丨智慧醫療解決方案精華版(58頁PPT)(文末有下載方式)

數字智慧方案6158丨智慧醫療解決方案精華版 詳細資料請看本解讀文章的最后內容。 引言 隨著信息技術的飛速發展&#xff0c;智慧醫療已成為現代醫療體系的重要組成部分。本文將對《數字智慧方案6158丨智慧醫療解決方案精華版》進行詳細解讀&#xff0c;探討如何通過先進的技…

Fiori學習專題二十三: Filtering

這節課我們將針對list增加一個篩選功能。 1.首先改造下InvoiceList.view.xml&#xff0c;加入id方便找到它以及標簽 <mvc:ViewcontrollerName"ui5.walkthrough.controller.InvoiceList"xmlns"sap.m"xmlns:core"sap.ui.core"xmlns:mvc"s…

大語言模型 05 運行、微調的顯存計算詳解與優化 全量微調、LoRA 優化策略

寫在前面 隨著Transformer架構的大語言模型&#xff08;LLM&#xff09;不斷發展&#xff0c;其參數規模也在迅速增加。無論是進行模型推理還是微調訓練&#xff0c;GPU顯存消耗都是開發和應用LLM時的重要考量。本文將詳細探討大模型運行&#xff08;推理&#xff09;與微調時…

對Electron打包的exe文件進行反解析

一、了解 Electron 打包的 exe&#xff0c;本質上就是打包了網頁 (HTMLCSSJS)&#xff0c;核心文件是 app.asar。超級容易還原&#xff0c;還原率接近 100% 為什么 Electron 特別容易&#xff1f; 因為 Electron 根本沒有真正編譯成機器碼&#xff0c;它只是把網頁資源&…

【Vue2】1-創建一個Vue實例

Vue2官方文檔 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title> </head&g…

【C語言練習】015. 聲明和初始化指針

015. 聲明和初始化指針 015. 聲明和初始化指針1. 聲明指針示例1:聲明一個指向整數的指針2. 初始化指針示例2:將指針初始化為`NULL`示例3:將指針初始化為某個變量的地址示例4:將指針初始化為動態分配的內存地址3. 使用指針訪問和修改變量的值示例5:使用指針訪問和修改變量的…

好未來golang后端開發

OSI網絡模型 TCP和UDP對比 HTTP和HTTPS對比 B樹 HTTP常見狀態碼 線程和進程的區別 goroutine的調度模型GMP 常見的排序了解哪些 快速排序 func quickSort(data []int) {if len(data) < 1 {return}base : data[0]l, r : 0, len(data)-1for i : 1; i < r; {if data[i] &g…

(持續更新)Ubuntu搭建LNMP(Linux + Nginx + MySQL + PHP)環境

LNMP&#xff08;Linux Nginx MySQL PHP&#xff09;環境是在Linux操作系統上構建的一個高性能Web服務器環境。M也可以指代其他數據庫&#xff0c;P也可以指代Python 1. 準備Linux系統 確保你已經在一臺服務器或虛擬機上安裝了Linux操作系統。推薦使用Ubuntu、CentOS或Debi…

服務器頻繁重啟日志分析與診斷

從你提供的日志來看&#xff0c;系統確實經歷了多次重啟。這個日志行顯示的是&#xff1a; reboot system boot 6.8.0-58-generic Tue Apr 29 17:54 - 14:26 (20:31)這表示系統在4月29日17:54啟動&#xff0c;運行了約20小時31分鐘后&#xff0c;于次日14:26結束&#xff08;可…

如何提升個人的穩定性?

提升自我的穩定性是一個系統性工程&#xff0c;需要從內在認知、情緒管理、行為習慣到外在環境等多個維度進行優化。 以下是一些具體建議&#xff0c;幫助你逐步增強內心的穩定感&#xff1a; 一、內在認知調整 1. 建立清晰的自我認知 通過反思&#xff08;如寫日記、冥想…

數值求解Eikonal方程的方法及開源實現

Eikonal方程是一類非線性偏微分方程&#xff0c;形式為 ( |\nabla u(x)| f(x) )&#xff0c;常見于波傳播、幾何光學、最短路徑等問題。以下是數值求解Eikonal方程的方法及開源實現參考&#xff1a; 一、數值求解方法 有限差分法&#xff08;FDM&#xff09; 快速行進法&#…

基于Redis實現-用戶簽到

基于Redis實現-用戶簽到 這個功能將使用到Redis中的BitMap來實現。 我們按照月來統計用戶簽到信息&#xff0c;簽到記錄為1&#xff0c;未簽到則記錄為0 把每一個bit位對應當月的每一天&#xff0c;形成了映射關系。用0和1標示業務狀態&#xff0c;這種思路稱為位圖(BitMap)。…

如何用GPU Instancing來優化樹木草石重復模型

1&#xff09;如何用GPU Instancing來優化樹木草石重復模型 2&#xff09;Unity ASTC壓縮后的紋理在部分安卓機型上不顯示 3&#xff09;現在大部分項目的豎版UI設計分辨率是多少 4&#xff09;Android上拖拽物體不實時跟隨手指的問題 這是第430篇UWA技術知識分享的推送&#x…