使用IRON SUITE

使用Iron Software程式庫的C# CancellationToken

Async/Await C#

現代軟體開發要求速度、響應性和無與倫比的可擴展性。 在網路應用和企業解決方案的世界中,阻塞UI執行緒或佔用伺服器資源是完全不可接受的。 這就是非同步程式設計,由功能強大的C#的async和await關鍵字驅動的地方,成為不僅僅是特性,而是必須的架構基礎。

對於利用高性能程式庫的開發者來說,如Iron Software套件中用於PDF生成、圖像操作和OCR的程式庫,了解如何編寫非同步程式碼是建造有效程式碼的關鍵,充分利用.NET任務並行程式庫的全部功能。

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

非同步程式設計的基本原理

async和await之前,非同步操作是通過繁瑣的回調和手動任務類操作來管理的,導致程式碼複雜且容易出錯。 C#中的非同步程式設計通過讓開發者編寫看上去像同步程式碼但行為是非同步的程式碼來簡化這個過程。

兩個核心組件是:

  1. async關鍵字:async修飾符將方法標記為可包含await表達式的非同步方法。 重要的是,將方法標記為async並不會自動將其運行在後台執行緒上。 它只是使編譯器能夠生成一個複雜的狀態機,以管理程式碼的繼續。 一般來說,async方法會返回一個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);
}
Imports System
Imports System.Net.Http
Imports System.Threading.Tasks

Public Module Program
    Public Async Function DownloadDataAsync(url As String) As Task(Of String)
        ' The async keyword allows us to use await
        Using client As New HttpClient()
            ' await task: Control returns to the caller while the HTTP call happens
            Dim data As String = Await client.GetStringAsync(url) ' I/O-bound 

            ' The code after the await expression runs once the task finishes
            Return $"Data length: {data.Length}"
        End Using
    End Function

    ' Modern entry point for console apps
    Public Async Function Main(args As String()) As Task
        ' This is the static async task main entry point
        Dim result As String = Await DownloadDataAsync("https://api.example.com/data")
        Console.WriteLine(result)
    End Function
End Module
$vbLabelText   $csharpLabel

使用static async task 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);
    });
}
Imports System.Threading.Tasks
Imports IronPdf

Public Module PdfGenerator
    Public Async Function GeneratePdfFromUrlAsync(url As String, outputFileName As String) As Task
        ' 1. Initialize the renderer
        Dim renderer As New ChromePdfRenderer()

        ' Optional: Set rendering options if needed (e.g., margins, headers)
        renderer.RenderingOptions.PaperSize = 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.
        Dim pdf = Await renderer.RenderUrlAsPdfAsync(url)

        ' 3. Save the PDF file asynchronously
        Await Task.Run(Sub()
                           ' This is the synchronous method you confirmed exists
                           pdf.SaveAs(outputFileName)
                       End Sub)
    End Function
End Module
$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;
}
Option Strict On



Public Async Function FetchAllDataAsync(url1 As String, url2 As String) As Task(Of String())
    ' Creating tasks starts the async operation immediately
    Dim taskA As Task(Of String) = DownloadDataAsync(url1)
    Dim taskB As Task(Of String) = DownloadDataAsync(url2)

    ' Wait for all the tasks to complete simultaneously
    Dim results As String() = Await Task.WhenAll(taskA, taskB)
    Return results
End Function
$vbLabelText   $csharpLabel

這是為並發運行的任務創造任務的標準模式,通過利用非阻塞的非同步操作急劇加速應用的響應時間。

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

當一個等待的任務完成時,預設行為是捕獲同步上下文並確保繼續運行在同一執行緒(如UI執行緒)上。 這對於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.
' Critical for shared libraries to avoid deadlocks and improve throughput
Dim data = Await GetVarDataFromRemoteServer().ConfigureAwait(False)
' This code continues on any thread, improving resource usage.
$vbLabelText   $csharpLabel

3. async 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);
}
Private Async Sub Button_Click(sender As Object, e As EventArgs) Handles Button.Click ' event handler
    ' This is one of the few places async void is acceptable
    Await GenerateReportAsync(html)
End Sub
$vbLabelText   $csharpLabel

任何其他使用async void方法的都是強烈不建議的。 由於async void方法無法被等待,調用執行緒無法追踪其完成或可靠地處理異常,因此錯誤處理很成問題。 對於所有其他非同步方法,始終返回Task或Task。

4. 異常處理

健壯的異常處理至關重要。 當一個非同步操作失敗(例如網路服務調用遭遇錯誤)時,異常會儲存在任務物件中。 當您等待任務時,await表達式將異常重新拋出到當前執行緒(即恢復繼續的執行緒),允許標準的try...catch塊有效地處理異常。

結論

C#中的async和await模式是一種範式轉變的特性,將開發者從脆弱的同步程式設計轉向更具韌性和可擴展的非同步方法。 通過了解底層狀態機並遵循最佳實踐——如優先使用Task而不是async void,在程式庫中使用ConfigureAwait(false),以及正確實施異常處理——開發者可以建立能夠以卓越性能處理複雜處理任務的應用(如Iron Software套件中的任務)。

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