C# 非同步程式設計

更新於 發佈於 閱讀時間約 9 分鐘

在 C# 中,非同步程式設計是一種有效提升應用性能、併發處理能力的重要技術。今天,我們將詳細介紹 C# 中的非同步核心概念:asyncawaitTaskTask<T>,說明它們的使用方式,並探討一些進階應用。最後,我們會簡單介紹一些非同步程式設計中常見的問題。


什麼是非同步程式設計?

非同步程式設計允許應用程式在處理長時間的操作(例如 I/O 操作或網絡請求)時,釋放執行緒資源來處理其他任務。這樣可以有效地提升應用性能,特別是在高併發的情況下,非同步程式設計讓伺服器可以同時處理更多的請求。


核心關鍵字與類型介紹

在 C# 中,非同步程式設計的核心由以下四個要素構成:

  • async
  • await
  • Task
  • Task<T>

這些工具使得我們可以有效地進行非同步操作,同時保持代碼的簡潔和易讀性。


1. async 關鍵字

async 是用來標記一個方法為非同步的關鍵字,允許你在方法內部使用 await 關鍵字來等待非同步操作完成。需要注意的是,async 本身不會讓一個方法變得非同步,它只是一個標記,允許該方法內部執行非同步操作。

語法與使用

public async Task<string> FetchDataAsync()
{
// 非同步操作
await Task.Delay(1000); // 模擬網路請求的延遲
return "Data fetched";
}

  • async 方法的返回類型:通常是 TaskTask<T>。如果不返回任何結果,可以使用 Task;如果返回結果,則使用 Task<T>

2. await 關鍵字

await 關鍵字用於等待一個非同步操作完成,並且在操作完成後繼續執行方法的剩餘部分。當一個方法執行到 await 時,執行緒將被釋放,允許其他任務併發執行。

語法與使用

public async Task<string> GetDataAsync()
{
// 等待非同步操作完成
var data = await FetchDataFromApiAsync();
return data;
}

  • await 的作用:防止應用程式阻塞,讓操作在後台完成,並保持代碼邏輯的清晰度和可讀性。

3. Task 類型

Task 是 C# 中表示非同步操作的基本類型。它代表一個未來會完成的操作,這個操作不會返回結果。Task 可以用於表示僅執行任務但不需要返回值的非同步方法。

語法與使用

public async Task PerformActionAsync()
{
await Task.Delay(1000); // 模擬非同步操作
}


4. Task<T> 類型

Task<T>Task 的泛型版本,它用來表示會返回結果的非同步操作。T 代表操作完成後返回的數據類型。

語法與使用

public async Task<string> FetchDataAsync()
{
await Task.Delay(1000); // 模擬非同步操作
return "Data fetched"; // 返回操作結果
}

  • Task<T> 的常見應用:例如,當從資料庫或 API 獲取數據時,通常會使用 Task<T>

進階應用:並行與性能優化


除了基本的 asyncawait,C# 提供了許多進階的非同步處理工具,這些工具在實現性能優化和更高併發度時非常有用。了解這些進階技術,可以幫助你更靈活地應用非同步程式設計並避免常見陷阱。


使用 Task.WhenAll 進行真正的並行處理

原理介紹

Task.WhenAll 是一個非常強大的工具,用於並行執行多個非同步任務。當你有多個彼此獨立的非同步操作時,Task.WhenAll 可以將這些操作同時進行,而不是按順序等待每個操作完成。它返回一個 Task,該 Task 在所有內部任務都完成時才會完成。這意味著它不會等待每個任務一個接一個地完成,而是讓它們同時執行,從而節省了時間。

應用場景

一個經典的應用場景是在處理多個 API 請求或同時進行多個 I/O 操作時。舉例來說,如果你的應用需要從多個來源下載數據,這些下載操作之間沒有相互依賴性,那麼使用 Task.WhenAll 可以顯著提高性能。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

public class Program
{
public static async Task Main(string[] args)
{
// 呼叫 FetchDataFromMultipleSourcesAsync 並取得結果
var urls = new List<string>
{
"<https://example.com/data1>",
"<https://example.com/data2>",
"<https://example.com/data3>"
};

var results = await FetchDataFromMultipleSourcesAsync(urls);

// 輸出每個請求的結果
foreach (var result in results)
{
Console.WriteLine(result);
}
}

public static async Task<IEnumerable<string>> FetchDataFromMultipleSourcesAsync(List<string> urls)
{
// 創建一個包含多個 Task 的集合,透過 HttpClient 發送非同步請求
var tasks = urls.Select(url => FetchDataAsync(url));

// 使用 Task.WhenAll 等待所有請求完成
var results = await Task.WhenAll(tasks);

return results;
}

// 模擬非同步的資料請求
public static async Task<string> FetchDataAsync(string url)
{
await Task.Delay(1000); // 模擬非同步延遲
return $"資料從 {url} 取得";
}
}


非同步程式設計的挑戰

在設計非同步程式時,開發者往往會遇到一些常見的挑戰。這些挑戰可能來自於非同步的特性,或是與系統架構相關的問題。以下是幾個常見的問題:

  • 資源競爭與併發控制:當多個非同步操作同時訪問共享資源時,可能會發生資源競爭,導致數據不一致。
  • 錯誤處理與異常恢復:在處理大量非同步操作時,如何有效地捕捉並處理錯誤成為一大挑戰,特別是在涉及網路或外部資源時。
  • 併發控制與限流:在高併發環境下,如果無法有效控制非同步任務的數量,可能會導致系統資源耗盡。
  • 非同步死鎖:不當的同步操作和非同步操作混合使用,可能導致應用程式出現死鎖,這是非同步設計中一個難以診斷的問題。

每日小結

在這篇文章中,我們詳細介紹了 C# 中的非同步程式設計,包括 asyncawaitTaskTask<T> 的基本使用方法和最佳實踐。我們還探討了一些進階應用,如如何使用 Task.WhenAll 並行處理非同步任務。

最後,我舉出幾個非同步程式設計常預見的問題,如資源競爭、錯誤處理、併發控制等。在下一篇文章中,我們將深入探討這些問題,並介紹具體的解決方案,幫助你在高併發和複雜環境中構建更加穩定和高效的非同步應用程式。並且會更完整介紹非同步API的設計架構。

留言
avatar-img
留言分享你的想法!
avatar-img
ChiYu Code Journey
0會員
12內容數
歡迎來到 ChiYu Code Journey!這裡是我分享技術心得與開發經驗的空間,主要內容涵蓋 C#、.Net、API 開發及雲端等程式主題。偶爾也會分享一些日常生活點滴,像是我與我家可愛的法鬥相處的趣事等。希望在這裡能和大家一起學習、交流,一同踏上這段程式旅程!
ChiYu Code Journey的其他內容
2025/01/23
在前一篇文章中,我們探討了非同步程式設計的基本概念,並介紹了如何使用 Task、Task<T>、async 和 await 來設計非同步操作。然而,非同步程式設計並非總是那麼直截了當。在實際開發中,開發者經常會遇到一些挑戰,這些挑戰主要來自於高併發、多執行緒以及非同步操作的特性。
2025/01/23
在前一篇文章中,我們探討了非同步程式設計的基本概念,並介紹了如何使用 Task、Task<T>、async 和 await 來設計非同步操作。然而,非同步程式設計並非總是那麼直截了當。在實際開發中,開發者經常會遇到一些挑戰,這些挑戰主要來自於高併發、多執行緒以及非同步操作的特性。
2025/01/21
這篇文章探討非同步編程的優缺點,並提供在設計非同步系統時需要注意的事項。非同步編程允許程式在等待 I/O 操作完成的同時,繼續執行其他工作,提高響應速度和資源利用率。然而,非同步程式設計也增加了系統複雜性,需要謹慎處理錯誤和確保代碼可讀性。
Thumbnail
2025/01/21
這篇文章探討非同步編程的優缺點,並提供在設計非同步系統時需要注意的事項。非同步編程允許程式在等待 I/O 操作完成的同時,繼續執行其他工作,提高響應速度和資源利用率。然而,非同步程式設計也增加了系統複雜性,需要謹慎處理錯誤和確保代碼可讀性。
Thumbnail
2025/01/21
RESTful API 設計原則與實務,包含資源導向設計、HTTP 方法使用、狀態碼應用、無狀態性、分頁排序、版本控制、避免過度設計等面向,並輔以優良與不良設計範例說明,最後以每日小結歸納重點。
2025/01/21
RESTful API 設計原則與實務,包含資源導向設計、HTTP 方法使用、狀態碼應用、無狀態性、分頁排序、版本控制、避免過度設計等面向,並輔以優良與不良設計範例說明,最後以每日小結歸納重點。
看更多
你可能也想看
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
「欸!這是在哪裡買的?求連結 🥺」 誰叫你太有品味,一發就讓大家跟著剁手手? 讓你回購再回購的生活好物,是時候該介紹出場了吧! 「開箱你的美好生活」現正召喚各路好物的開箱使者 🤩
Thumbnail
本篇文章介紹 Python 的 asyncio 標準庫,說明其用於非同步編程的優勢,並深入探討 await, asyncio.create_task(), asyncio.gather() 的用法與差異,以提升 I/O 密集型應用的效能。
Thumbnail
本篇文章介紹 Python 的 asyncio 標準庫,說明其用於非同步編程的優勢,並深入探討 await, asyncio.create_task(), asyncio.gather() 的用法與差異,以提升 I/O 密集型應用的效能。
Thumbnail
.NET 執行緒池是重要的非同步觀念,async 和 await 底層機制之一。本文探討執行緒池如何有效管理及重複使用執行緒,避免頻繁創建和銷毀執行緒的開銷,並比較 Task.Run 與直接創建 Thread 的差異,以及在精確計時任務方面可能面臨的挑戰。
Thumbnail
.NET 執行緒池是重要的非同步觀念,async 和 await 底層機制之一。本文探討執行緒池如何有效管理及重複使用執行緒,避免頻繁創建和銷毀執行緒的開銷,並比較 Task.Run 與直接創建 Thread 的差異,以及在精確計時任務方面可能面臨的挑戰。
Thumbnail
這篇文章探討非同步編程的優缺點,並提供在設計非同步系統時需要注意的事項。非同步編程允許程式在等待 I/O 操作完成的同時,繼續執行其他工作,提高響應速度和資源利用率。然而,非同步程式設計也增加了系統複雜性,需要謹慎處理錯誤和確保代碼可讀性。
Thumbnail
這篇文章探討非同步編程的優缺點,並提供在設計非同步系統時需要注意的事項。非同步編程允許程式在等待 I/O 操作完成的同時,繼續執行其他工作,提高響應速度和資源利用率。然而,非同步程式設計也增加了系統複雜性,需要謹慎處理錯誤和確保代碼可讀性。
Thumbnail
在JavaScript裡面,Async和Await應該是搜尋熱度最高的關鍵字了,因為他們相對複雜。我們一步步討論這件事的歷史 — 它們為什麼出現,解決了什麼問題。 JavaScript的Synchronous(同步) 首先我們必須了解JavaScript執行的基本原則 — synchrono
Thumbnail
在JavaScript裡面,Async和Await應該是搜尋熱度最高的關鍵字了,因為他們相對複雜。我們一步步討論這件事的歷史 — 它們為什麼出現,解決了什麼問題。 JavaScript的Synchronous(同步) 首先我們必須了解JavaScript執行的基本原則 — synchrono
Thumbnail
本文探討 C# 非同步程式設計時應注意的幾個要點,包括全面採用非同步模式、避免混用同步與非同步程式碼、勿使用async void、以及正確使用CancellationToken等。這些建議不僅有助於提升程式的效能,也可以減少Deadlock等問題,讓開發者更有效地處理異常情況,確保應用程式的穩定性.
Thumbnail
本文探討 C# 非同步程式設計時應注意的幾個要點,包括全面採用非同步模式、避免混用同步與非同步程式碼、勿使用async void、以及正確使用CancellationToken等。這些建議不僅有助於提升程式的效能,也可以減少Deadlock等問題,讓開發者更有效地處理異常情況,確保應用程式的穩定性.
Thumbnail
任何語言特性用與不用,其實要看是否提升了生產力?是否提升可讀性?是否提升可維護性?這些都是在三個月甚至半年後回來修改程式時,才能明顯感受到的,而不是寫程式的當下。Java 8 的 CompletableFuture、Stream 和 Optional 都很好,但用的不好反而畫蛇添足又沒提高可讀性。
Thumbnail
任何語言特性用與不用,其實要看是否提升了生產力?是否提升可讀性?是否提升可維護性?這些都是在三個月甚至半年後回來修改程式時,才能明顯感受到的,而不是寫程式的當下。Java 8 的 CompletableFuture、Stream 和 Optional 都很好,但用的不好反而畫蛇添足又沒提高可讀性。
Thumbnail
這篇文章將會快速介紹非同步函式(Async / Await)的簡易使用方式。
Thumbnail
這篇文章將會快速介紹非同步函式(Async / Await)的簡易使用方式。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News