使用IRON SUITE

掌握 .NET 10 中的 Async/Await C#:可擴展應用程式的基本指南

Async/Await C#

現代軟體開發需要速度、反應能力和無與倫比的可擴展性。 在 Web 應用和企業解決方案領域,阻塞 UI 執行緒或佔用伺服器資源是絕對不可接受的。 正是在這裡,由C# 中強大的 async 和 await 關鍵字支援的非同步編程,不僅成為一項功能,而且成為一項必不可少的架構基礎。

對於使用高效能函式庫(例如用於PDF 生成、影像處理和OCR的 Iron Software套件)的開發人員來說,了解如何編寫非同步程式碼是建立高效程式碼的關鍵,從而充分利用.NET任務並行庫的強大功能。

我們將深入探討 C# 的 async/await 機制,探索這種範式轉變如何將緩慢的同步編程轉變為高吞吐量的非同步操作,並將這些關鍵概念與Iron Software如何幫助企業實現最大效能聯繫起來。

非同步程式設計基礎

async 和 await出現之前,非同步操作是透過繁瑣的回呼和手動 Task 類別操作來管理的,這導致程式碼複雜且容易出錯。 C# 中的非同步程式簡化了這個過程,讓開發人員編寫看起來像同步程式碼但行為非同步的程式碼。

這兩個核心組成部分是:

  1. async 關鍵字: async 修飾符將方法標記為非同步方法,該方法可以包含 await 表達式。 關鍵在於,將方法標記為非同步並不會自動在後台執行緒上執行它。 它只是讓編譯器產生一個複雜的狀態機來管理程式碼的後續執行。 非同步方法通常會傳回一個 Task 物件(Task 或 Task)。 ) 表示正在進行的非同步任務。

  2. await 關鍵字: await 關鍵字是神奇的組成部分。 當遇到 await 表達式時,此方法會檢查等待的任務是否已完成。 如果還沒有執行,則該方法會立即暫停執行並將控制權傳回給呼叫方法(或呼叫者)。 這將釋放當前線程(通常是主線程或線程池線程)以處理其他請求或其他任務。 當任務完成後,該方法的剩餘部分將註冊為延續,並重新安排運行。

以下是一個基礎程式碼範例:

public static async Task<string> DownloadDataAsync(string url)
{
    // The async keyword allows us to use await
    using var client = new HttpClient();

    // await task: Control returns to the caller while the HTTP call happens
    string data = await client.GetStringAsync(url); // I/O-bound 

    // The code after the await expression runs once the task finishes
    return $"Data length: {data.Length}";
}

// Modern entry point for console apps
public static async Task Main(string[] args) 
{
    // This is the static async task main entry point
    var result = await DownloadDataAsync("https://api.example.com/data");
    Console.WriteLine(result);
}
public static async Task<string> DownloadDataAsync(string url)
{
    // The async keyword allows us to use await
    using var client = new HttpClient();

    // await task: Control returns to the caller while the HTTP call happens
    string data = await client.GetStringAsync(url); // I/O-bound 

    // The code after the await expression runs once the task finishes
    return $"Data length: {data.Length}";
}

// Modern entry point for console apps
public static async Task Main(string[] args) 
{
    // This is the static async task main entry point
    var result = await DownloadDataAsync("https://api.example.com/data");
    Console.WriteLine(result);
}
$vbLabelText   $csharpLabel

使用靜態非同步任務 main 是現代標準,無需使用 .Wait() 或 .Result 等舊方法來阻塞主執行緒。

性能和Iron Software集成

雖然 Task 是非同步程式碼的標準回傳類型,但在.NET 10 中,高階非同步程式設計通常會使用 ValueTask。對於可能出現同步完成的"熱路徑"(例如,檢索快取值),可以顯著提高效能。 ValueTask 避免了記憶體分配,因此對於高吞吐量應用程式至關重要。

將非同步操作應用於Iron Software

Iron Software 的產品,如IronOCR (光學字元辨識)和IronPDF (PDF 產生),非常適合利用非同步呼叫。 將大型 HTML 文件轉換為 PDF 或掃描數百頁圖像以獲取文字等操作通常是 CPU 密集型任務或涉及文件系統 I/O,非同步方法可以大大提高這些任務的效率。

使用Iron Software提供的同步和非同步方法,可以確保您的應用程式保持高度響應性。

可以考慮使用IronPDF從指定的 URL建立文件

public static async Task GeneratePdfFromUrlAsync(string url, string outputFileName)
{
    // 1. Initialize the renderer
    var renderer = new IronPdf.ChromePdfRenderer();

    // Optional: Set rendering options if needed (e.g., margins, headers)
    renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;

    // 2. The core asynchronous operation: Fetch and render the URL content
    // This is an I/O-bound task that releases the calling thread.
    var pdf = await renderer.RenderUrlAsPdfAsync(url);

    // 3. Save the PDF file asynchronously
    await Task.Run(() =>
    {
        // This is the synchronous method you confirmed exists
        pdf.SaveAs(outputFileName);
    });
}
public static async Task GeneratePdfFromUrlAsync(string url, string outputFileName)
{
    // 1. Initialize the renderer
    var renderer = new IronPdf.ChromePdfRenderer();

    // Optional: Set rendering options if needed (e.g., margins, headers)
    renderer.RenderingOptions.PaperSize = IronPdf.Rendering.PdfPaperSize.A4;

    // 2. The core asynchronous operation: Fetch and render the URL content
    // This is an I/O-bound task that releases the calling thread.
    var pdf = await renderer.RenderUrlAsPdfAsync(url);

    // 3. Save the PDF file asynchronously
    await Task.Run(() =>
    {
        // This is the synchronous method you confirmed exists
        pdf.SaveAs(outputFileName);
    });
}
$vbLabelText   $csharpLabel

使用非同步方法產生的 PDF

PDF 非同步渲染

透過使用 RenderHtmlAsPdfAsync() 非同步方法,我們可以防止應用程式在處理大型文件時出現凍結或阻塞。 這演示瞭如何有效地編寫非同步程式碼以進行複雜處理。

最佳實務和特殊情況

1. 處理多個任務和 I/O

為了最大限度地提高效率,在等待獨立的 I/O 密集型工作(例如從遠端伺服器取得資料或執行資料庫查詢)時,應該同時啟動多個任務。

public async Task<string[]> FetchAllDataAsync(string url1, string url2)
{
    // Creating tasks starts the async operation immediately
    Task<string> taskA = DownloadDataAsync(url1); 
    Task<string> taskB = DownloadDataAsync(url2);

    // Wait for all the tasks to complete simultaneously
    string[] results = await Task.WhenAll(taskA, taskB);
    return results;
}
public async Task<string[]> FetchAllDataAsync(string url1, string url2)
{
    // Creating tasks starts the async operation immediately
    Task<string> taskA = DownloadDataAsync(url1); 
    Task<string> taskB = DownloadDataAsync(url2);

    // Wait for all the tasks to complete simultaneously
    string[] results = await Task.WhenAll(taskA, taskB);
    return results;
}
$vbLabelText   $csharpLabel

這是創建並發運行任務的標準模式,透過利用非阻塞非同步操作,顯著加快應用程式回應時間。

2. 同步上下文和 ConfigureAwait(false)

當等待的任務完成時,預設行為是捕獲同步上下文,並確保後續操作在同一執行緒(如 UI 執行緒)上運行。 這對於使用者介面應用程式至關重要,但會為伺服器端或程式庫程式碼帶來不必要的開銷。

使用 ConfigureAwait(false) 會告訴執行階段,await 呼叫後的程式碼可以在任何可用的執行緒池後台執行緒上恢復執行。 對於庫開發者而言,這是一項至關重要的實踐,能夠確保非同步操作發揮最大效能:

// Critical for shared libraries to avoid deadlocks and improve throughput
var data = await GetVarDataFromRemoteServer().ConfigureAwait(false); 
// This code continues on any thread, improving resource usage.
// Critical for shared libraries to avoid deadlocks and improve throughput
var data = await GetVarDataFromRemoteServer().ConfigureAwait(false); 
// This code continues on any thread, improving resource usage.
$vbLabelText   $csharpLabel

3. 非同步 void 的危險

非同步程式設計中最關鍵的規則之一是,除了非同步事件處理程序之外,永遠不要使用 async void。 例如,按鈕點擊事件處理方法通常會使用 async void:

private async void Button_Click(object sender, EventArgs e) // event handler
{
    // This is one of the few places async void is acceptable
    await GenerateReportAsync(html);
}
private async void Button_Click(object sender, EventArgs e) // event handler
{
    // This is one of the few places async void is acceptable
    await GenerateReportAsync(html);
}
$vbLabelText   $csharpLabel

強烈不建議以任何其他方式使用非同步 void 方法。 由於非同步 void 方法不能被等待處理,因此呼叫執行緒無法追蹤其完成情況或可靠地處理異常,這使得錯誤處理變得困難。 始終返回任務或任務對於所有其他非同步方法。

4. 異常處理

健全的異常處理機制至關重要。 當非同步操作失敗時(例如,Web 服務呼叫遇到錯誤),異常會儲存在任務物件中。 當您等待任務完成時,await 表達式會將例外狀況重新拋出到目前執行緒(即恢復執行的執行緒),從而使標準的 try...catch 區塊能夠有效地進行例外處理。

結論

C# 中的 async 和 await 模式是一項顛覆性的功能,它使開發人員擺脫脆弱的同步編程,轉向彈性、可擴展的非同步方法。 透過理解底層狀態機並遵循最佳實踐(例如,優先處理任務),可以提高效率。透過對 async void 進行處理,在庫中使用 ConfigureAwait(false),並正確實現異常處理——開發人員可以創建能夠以卓越的性能處理複雜處理任務(例如 Iron Software 套件中的任務)的應用程式。

Iron Software致力於開發以高效能非同步程式設計為核心的產品,確保您的程式碼編寫實踐能夠實現最大吞吐量。 探索Iron Software的世界,了解如何利用非同步任務處理顯著提升應用程式的速度和反應能力。