使用 IRON SUITE

在 .NET 10 中掌握 Async/Await C#:可扩展应用程序的基本指南

! Async/Await C#

现代软件开发要求速度、响应速度和无与伦比的可扩展性。 在网络应用程序和企业解决方案的世界里,阻塞用户界面线程或占用服务器资源是根本无法接受的。 这时,由 C# 中强大的 async 和 await 关键字提供支持的异步编程就不仅仅是一种功能,而是一种强制性的架构基础。

对于使用高性能库(如用于 PDF 生成、图像处理和 OCRIron Software Suite)的开发人员来说,了解如何编写异步代码是构建高效代码、充分利用 .NET 任务并行库全部功能的关键。

我们将深入探讨 async/ await C# 的机制,探讨这种模式转变如何将缓慢的同步编程转变为高吞吐量的异步操作,并将这些关键概念与 Iron Software 如何帮助企业实现最高性能联系起来。

异步编程基础

async和await之前,异步操作是通过繁琐的回调和手动任务类操作来管理的,导致代码复杂且容易出错。 C# 中的异步编程简化了这一点,它允许开发人员编写看起来是同步代码但行为却是异步的代码。

两个核心组成部分是

1.async 关键字:async 修饰符将方法标记为可包含 await 表达式的 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);
}
$vbLabelText   $csharpLabel

使用静态异步任务 main 是现代标准,无需使用 .Wait() 或 .Result 等传统方法阻塞主线程。

性能与 Iron 软件集成

虽然 Task 是异步代码的标准返回类型,但在 .NET 10 中,高级异步编程通常会使用 ValueTask。对于可能出现同步完成的"热路径"(例如,检索缓存值),可以显著提高性能。 ValueTask 可避免内存分配,因此对高吞吐量应用程序至关重要。

将异步操作应用于 Iron 软件

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.

!a href="/static-assets/ironsoftware/suite/blog/async-await-csharp-net10/async-await-csharp-net10-2.webp">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.同步上下文和配置等待(false)

当等待的任务完成时,默认行为是捕获同步上下文并确保在同一线程(如用户界面线程)上继续运行。 这对用户界面应用程序至关重要,但会给服务器端或库代码带来不必要的开销。

使用 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.async void 的危险

异步编程中最重要的规则之一是,除了异步事件处理程序外,永远不要使用异步 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.异常处理

稳健的异常处理至关重要。 当异步操作失败时(如网络服务调用遇到错误),异常会存储在任务对象中。 在等待任务时,await 表达式会将异常重新抛给当前线程(继续执行任务的线程),从而使标准 try...catch 块能够有效地处理异常。

结论

C# 中的 async 和 await 模式是一种模式转换功能,它使开发人员从脆性同步编程转向弹性、可扩展的异步方法。 通过理解底层状态机并遵循最佳实践(例如,优先处理任务),可以提高效率。通过对 async void 进行处理,在库中使用 ConfigureAwait(false),并正确实现异常处理——开发人员可以创建能够以卓越的性能处理复杂处理任务(例如 Iron Software 套件中的任务)的应用程序。

Iron Software 致力于开发以高性能异步编程为核心的产品,确保您的代码编写实践能够带来最大的吞吐量。 探索 Iron Software 的世界,了解利用异步任务处理如何显著提高应用程序的速度和响应能力