如何在C#中使用异步和多线程生成PDF文件

如何使用 C# 异步和多线程生成 PDF

This article was translated from English: Does it need improvement?
Translated
View the article in English

IronPDF 可在 C# 中使用异步操作和多线程实现高性能 PDF 生成,与复杂 HTML 渲染场景的同步方法相比,批处理时间最多可缩短 65%。

快速入门:使用IronPDF异步将 HTML 转换为 PDF

只需几行代码,即可使用IronPDF开始异步PDF生成。

使用RenderHtmlAsPdfAsync方法,您可以高效地将HTML内容转换为PDF,优化您的应用程序性能。 本指南介绍了如何利用异步操作生成高性能 PDF,非常适合批处理和多线程环境。

  1. 使用 NuGet 包管理器安装 https://www.nuget.org/packages/IronPdf

    PM > Install-Package IronPdf
  2. 复制并运行这段代码。

    var pdf = await IronPdf.ChromePdfRenderer.RenderHtmlAsPdfAsync("<h1>Hello World!</h1>");
  3. 部署到您的生产环境中进行测试

    通过免费试用立即在您的项目中开始使用IronPDF

    arrow pointer


如何在 C# 中实现异步 PDF 生成?

IronPDF完全支持使用渲染方法如RenderHtmlAsPdfAsync的异步操作。 IronPDF 中的 async 实现利用基于任务的异步模式 (TAP) 来实现非阻塞 PDF 生成操作。 这种方法有利于复杂的 HTML 内容渲染或同步 PDF 请求处理。 有关完整的方法参考,请参阅 渲染方法文档

异步生成 PDF 可防止桌面应用程序的 UI 冻结,并提高网络应用程序的请求吞吐量。 使用await模式允许您的应用程序在等待PDF渲染完成时处理其他操作,从而显著增强响应能力和用户体验。

为什么要使用异步方法生成 PDF?

异步方法为 PDF 生成工作流提供了关键优势。 这些工具可在资源密集型操作过程中保持应用程序的响应速度,在多核处理器上提高资源利用率,并改善服务器环境的可扩展性。 在处理 复杂的 HTML 至 PDF 转换时,异步操作可防止超时问题并改善用户体验。

:path=/static-assets/pdf/content-code-examples/how-to/async-async.cs
using IronPdf;
using System.Threading.Tasks;

// Instantiate ChromePdfRenderer
ChromePdfRenderer renderer = new ChromePdfRenderer();

string[] htmlStrings = {"<h1>Html 1</h1>", "<h1>Html 2</h1>", "<h1>Html 3</h1>"};

// Create an array to store the tasks for rendering
var renderingTasks = new Task<PdfDocument>[htmlStrings.Length];

for (int i = 0; i < htmlStrings.Length; i++)
{
    int index = i; // Capturing the loop variable
    renderingTasks[i] = Task.Run(async () =>
    {
        // Render HTML to PDF
        return await renderer.RenderHtmlAsPdfAsync(htmlStrings[index]);
    });
}

// Wait for all rendering tasks to complete
// await Task.WhenAll(renderingTasks);
Imports IronPdf
Imports System.Threading.Tasks

' Instantiate ChromePdfRenderer
Private renderer As New ChromePdfRenderer()

Private htmlStrings() As String = {"<h1>Html 1</h1>", "<h1>Html 2</h1>", "<h1>Html 3</h1>"}

' Create an array to store the tasks for rendering
Private renderingTasks = New Task(Of PdfDocument)(htmlStrings.Length - 1){}

For i As Integer = 0 To htmlStrings.Length - 1
	Dim index As Integer = i ' Capturing the loop variable
	renderingTasks(i) = Task.Run(Async Function()
		' Render HTML to PDF
		Return Await renderer.RenderHtmlAsPdfAsync(htmlStrings(index))
	End Function)
Next i

' Wait for all rendering tasks to complete
' await Task.WhenAll(renderingTasks);
$vbLabelText   $csharpLabel

批处理的常见模式有哪些?

批量处理 PDF 需要仔细考虑内存使用和性能。 有效的模式包括使用Task.WhenAll并行执行多个PDF生成,通过通道实现生产者-消费者模式处理大型批次,并利用来自IronPDF文档的并行处理示例

// Batch processing with progress tracking
public async Task<List<PdfDocument>> ProcessBatchAsync(List<string> htmlContents, IProgress<int> progress)
{
    var renderer = new ChromePdfRenderer();
    var results = new List<PdfDocument>();
    var completed = 0;

    var tasks = htmlContents.Select(async html => {
        var pdf = await renderer.RenderHtmlAsPdfAsync(html);
        Interlocked.Increment(ref completed);
        progress?.Report(completed);
        return pdf;
    });

    results.AddRange(await Task.WhenAll(tasks));
    return results;
}
// Batch processing with progress tracking
public async Task<List<PdfDocument>> ProcessBatchAsync(List<string> htmlContents, IProgress<int> progress)
{
    var renderer = new ChromePdfRenderer();
    var results = new List<PdfDocument>();
    var completed = 0;

    var tasks = htmlContents.Select(async html => {
        var pdf = await renderer.RenderHtmlAsPdfAsync(html);
        Interlocked.Increment(ref completed);
        progress?.Report(completed);
        return pdf;
    });

    results.AddRange(await Task.WhenAll(tasks));
    return results;
}
Imports System.Collections.Generic
Imports System.Threading
Imports System.Threading.Tasks

' Batch processing with progress tracking
Public Async Function ProcessBatchAsync(htmlContents As List(Of String), progress As IProgress(Of Integer)) As Task(Of List(Of PdfDocument))
    Dim renderer As New ChromePdfRenderer()
    Dim results As New List(Of PdfDocument)()
    Dim completed As Integer = 0

    Dim tasks = htmlContents.Select(Async Function(html)
                                        Dim pdf = Await renderer.RenderHtmlAsPdfAsync(html)
                                        Interlocked.Increment(completed)
                                        progress?.Report(completed)
                                        Return pdf
                                    End Function)

    results.AddRange(Await Task.WhenAll(tasks))
    Return results
End Function
$vbLabelText   $csharpLabel

如何处理异步 PDF 操作中的错误?

异步 PDF 操作中的错误处理需要全面的异常管理策略。 在异步方法中使用Polly实现高级重试策略。 对于详细的性能故障排除,IronPDF 提供了广泛的日志功能。

public async Task<PdfDocument> RenderWithRetryAsync(string html, int maxRetries = 3)
{
    var renderer = new ChromePdfRenderer();

    for (int i = 0; i < maxRetries; i++)
    {
        try
        {
            return await renderer.RenderHtmlAsPdfAsync(html);
        }
        catch (Exception ex) when (i < maxRetries - 1)
        {
            // Log the exception
            await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, i))); // Exponential backoff
        }
    }

    throw new InvalidOperationException("Failed to render PDF after maximum retries");
}
public async Task<PdfDocument> RenderWithRetryAsync(string html, int maxRetries = 3)
{
    var renderer = new ChromePdfRenderer();

    for (int i = 0; i < maxRetries; i++)
    {
        try
        {
            return await renderer.RenderHtmlAsPdfAsync(html);
        }
        catch (Exception ex) when (i < maxRetries - 1)
        {
            // Log the exception
            await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, i))); // Exponential backoff
        }
    }

    throw new InvalidOperationException("Failed to render PDF after maximum retries");
}
Imports System
Imports System.Threading.Tasks

Public Class PdfRenderer
    Public Async Function RenderWithRetryAsync(html As String, Optional maxRetries As Integer = 3) As Task(Of PdfDocument)
        Dim renderer As New ChromePdfRenderer()

        For i As Integer = 0 To maxRetries - 1
            Try
                Return Await renderer.RenderHtmlAsPdfAsync(html)
            Catch ex As Exception When i < maxRetries - 1
                ' Log the exception
                Await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, i))) ' Exponential backoff
            End Try
        Next

        Throw New InvalidOperationException("Failed to render PDF after maximum retries")
    End Function
End Class
$vbLabelText   $csharpLabel
Icon Quote related to 如何处理异步 PDF 操作中的错误?

我最喜欢的这种库是 IronPDF。它允许快速高效地操作 PDF 文件。它还具有许多有价值的功能,比如导出为 PDF/A 格式和数字签名 PDF 文档。

Milan Jovanovic related to 如何处理异步 PDF 操作中的错误?

Milan Jovanovic

微软MVP

查看案例研究
Icon Quote related to 如何处理异步 PDF 操作中的错误?

IronOCR 意味着我们每年可以节省 $40,000 的人工处理成本,同时提高生产力,并释放资源用于高影响任务。我强烈推荐它。

Brent Matzelle related to 如何处理异步 PDF 操作中的错误?

Brent Matzelle

首席技术官,OPYN

查看案例研究
Icon Quote related to 如何处理异步 PDF 操作中的错误?

Iron Suite 在我们的运营中起着至关重要的作用。这些工具提高了业务各方面的效率,包括创建平面图和改善库存管理。

David Jones related to 如何处理异步 PDF 操作中的错误?

David Jones

首席软件工程师,Agorus Build

查看案例研究

如何使用多线程生成 PDF?

IronPDF是线程安全的,支持使用ChromePdfRenderer渲染引擎的多线程。请注意,macOS机器上的多线程是有限的。 Chrome渲染引擎为并发操作提供了出色的线程安全和性能特性。

Parallel.ForEach模式适合于批量处理PDF,使您能够有效利用所有可用的CPU核心。 有关全面的多线程生成示例,请参阅 IronPDF 文档。

何时应选择多线程而非异步?

多线程非常适合需要在系统资源充足的情况下同时处理多个 PDF 的 CPU 绑定操作。 当在多核系统上处理大批量 PDF 时,当每个 PDF 生成都是独立的,当内存使用可以控制时,请选择多线程。 异步更适合 I/O 绑定操作和保持应用程序的响应速度。

线程安全注意事项有哪些?

IronPDF的ChromePdfRenderer设计为线程安全,但有某些考虑需要注意。 在使用自定义设置时为每个线程创建单独的渲染器实例,避免在线程之间共享PdfDocument实例而不进行同步,并监视处理大型文档时的内存消耗。 安装概述提供了有关配置 IronPDF 以优化线程安全的其他详细信息。

// Thread-safe PDF generation with custom settings per thread
public void ProcessPdfsInParallel(List<string> htmlContents)
{
    Parallel.ForEach(htmlContents, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, 
        html =>
        {
            // Create a new renderer instance for each thread
            var renderer = new ChromePdfRenderer
            {
                RenderingOptions = new ChromePdfRenderOptions
                {
                    MarginTop = 10,
                    MarginBottom = 10,
                    PaperSize = IronPdf.Rendering.PdfPaperSize.A4
                }
            };

            var pdf = renderer.RenderHtmlAsPdf(html);
            pdf.SaveAs($"output_{Thread.CurrentThread.ManagedThreadId}_{DateTime.Now.Ticks}.pdf");
        });
}
// Thread-safe PDF generation with custom settings per thread
public void ProcessPdfsInParallel(List<string> htmlContents)
{
    Parallel.ForEach(htmlContents, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }, 
        html =>
        {
            // Create a new renderer instance for each thread
            var renderer = new ChromePdfRenderer
            {
                RenderingOptions = new ChromePdfRenderOptions
                {
                    MarginTop = 10,
                    MarginBottom = 10,
                    PaperSize = IronPdf.Rendering.PdfPaperSize.A4
                }
            };

            var pdf = renderer.RenderHtmlAsPdf(html);
            pdf.SaveAs($"output_{Thread.CurrentThread.ManagedThreadId}_{DateTime.Now.Ticks}.pdf");
        });
}
Imports System
Imports System.Collections.Generic
Imports System.Threading
Imports System.Threading.Tasks
Imports IronPdf

' Thread-safe PDF generation with custom settings per thread
Public Sub ProcessPdfsInParallel(htmlContents As List(Of String))
    Parallel.ForEach(htmlContents, New ParallelOptions With {.MaxDegreeOfParallelism = Environment.ProcessorCount},
        Sub(html)
            ' Create a new renderer instance for each thread
            Dim renderer = New ChromePdfRenderer With {
                .RenderingOptions = New ChromePdfRenderOptions With {
                    .MarginTop = 10,
                    .MarginBottom = 10,
                    .PaperSize = IronPdf.Rendering.PdfPaperSize.A4
                }
            }

            Dim pdf = renderer.RenderHtmlAsPdf(html)
            pdf.SaveAs($"output_{Thread.CurrentThread.ManagedThreadId}_{DateTime.Now.Ticks}.pdf")
        End Sub)
End Sub
$vbLabelText   $csharpLabel

我应该使用多少并发线程?

并发线程的最佳数量取决于 CPU 内核、可用内存和 PDF 复杂性。 一般指导方针包括在CPU密集型操作中使用Environment.ProcessorCount,对内存密集型PDF限制为2-4个线程,并监视系统资源以找到最佳配置。 async示例演示了各种线程策略。

我可以期待哪些性能改进?

比较显示,不同渲染方法之间存在明显的性能差异。 在使用WaitFor类渲染时加入5秒延迟,模拟复杂的HTML渲染。 以下是使用上述各种技术的性能比较表。

为什么异步比同步性能更好?

正常渲染 异步渲染 多线程渲染
15.75 秒 05.59 秒 05.68 秒

异步操作之所以出色,是因为它们可以实现高效的线程池资源管理,防止主线程阻塞,并在 I/O 操作过程中提高 CPU 的利用率。 性能的提高来自于同时启动多个渲染操作,而不是等待每个操作按顺序完成。

如何衡量应用程序的性能?

衡量 PDF 生成性能需要适当的基准测试和监控。 使用System.Diagnostics.Stopwatch进行精确的时间测量,实施自定义性能计数器用于生产监控,并利用应用程序洞察或类似APM工具。 考虑使用快速入门指南示例作为性能测试的基准。

public async Task<PerformanceMetrics> MeasurePerformanceAsync(string html, int iterations)
{
    var metrics = new PerformanceMetrics();
    var renderer = new ChromePdfRenderer();
    var stopwatch = new Stopwatch();

    // Warm-up run
    await renderer.RenderHtmlAsPdfAsync(html);

    for (int i = 0; i < iterations; i++)
    {
        stopwatch.Restart();
        await renderer.RenderHtmlAsPdfAsync(html);
        stopwatch.Stop();

        metrics.AddMeasurement(stopwatch.ElapsedMilliseconds);
    }

    return metrics;
}
public async Task<PerformanceMetrics> MeasurePerformanceAsync(string html, int iterations)
{
    var metrics = new PerformanceMetrics();
    var renderer = new ChromePdfRenderer();
    var stopwatch = new Stopwatch();

    // Warm-up run
    await renderer.RenderHtmlAsPdfAsync(html);

    for (int i = 0; i < iterations; i++)
    {
        stopwatch.Restart();
        await renderer.RenderHtmlAsPdfAsync(html);
        stopwatch.Stop();

        metrics.AddMeasurement(stopwatch.ElapsedMilliseconds);
    }

    return metrics;
}
Imports System.Diagnostics
Imports System.Threading.Tasks

Public Class PerformanceMetrics
    ' Assume this class has an AddMeasurement method
    Public Sub AddMeasurement(milliseconds As Long)
        ' Implementation here
    End Sub
End Class

Public Class ChromePdfRenderer
    ' Assume this class has a RenderHtmlAsPdfAsync method
    Public Async Function RenderHtmlAsPdfAsync(html As String) As Task
        ' Implementation here
    End Function
End Class

Public Class PerformanceTester
    Public Async Function MeasurePerformanceAsync(html As String, iterations As Integer) As Task(Of PerformanceMetrics)
        Dim metrics As New PerformanceMetrics()
        Dim renderer As New ChromePdfRenderer()
        Dim stopwatch As New Stopwatch()

        ' Warm-up run
        Await renderer.RenderHtmlAsPdfAsync(html)

        For i As Integer = 0 To iterations - 1
            stopwatch.Restart()
            Await renderer.RenderHtmlAsPdfAsync(html)
            stopwatch.Stop()

            metrics.AddMeasurement(stopwatch.ElapsedMilliseconds)
        Next

        Return metrics
    End Function
End Class
$vbLabelText   $csharpLabel

影响 PDF 生成速度的因素有哪些?

影响 PDF 生成性能的因素有很多。 HTML 的复杂性,包括 JavaScript 的执行和 CSS 的渲染,会直接影响处理时间。外部资源加载(如图像和字体)也会造成延迟。 CPU、内存和磁盘 I/O 等系统资源起着至关重要的作用。 IronPDF 配置(包括渲染选项和引擎设置)也会影响速度。 了解这些因素有助于优化 PDF 生成工作流程,实现最高效率。

对于涉及大量 JavaScript 或延迟渲染的复杂场景,请考虑使用 WaitFor 机制,以确保在生成 PDF 之前完成页面渲染。 这种方法既能保证准确的输出,又能保持可预测的性能特征。

常见问题解答

使用异步 PDF 生成技术能提高多少性能?

与同步方法相比,IronPDF 的异步操作和多线程可将批处理时间最多缩短 65%,尤其是在渲染复杂的 HTML 内容时。实际性能提升取决于 HTML 复杂性、系统资源和并发操作数量等因素。

将 HTML 异步转换为 PDF 的最简单方法是什么?

最简单的方法是使用 IronPDF 的 RenderHtmlAsPdfAsync 方法。只需一行代码`var pdf = await IronPdf.ChromePdfRenderer.RenderHtmlAsPdfAsync("Hello World!");`,您就可以高效地将 HTML 内容转换为 PDF,同时保持应用程序的响应速度。

为什么要使用异步方法而不是同步生成 PDF?

IronPDF 中的异步方法可以防止桌面应用程序中的 UI 冻结,提高网络应用程序中的请求吞吐量,在多核处理器上更好地利用资源,并增强服务器环境中的可扩展性。在处理复杂的 HTML 到 PDF 转换或同时处理多个 PDF 请求时,异步方法尤其有用。

该库使用什么异步模式进行 PDF 操作?

IronPDF 为其异步操作实现了基于任务的异步模式(TAP),包括 RenderHtmlAsPdfAsync 等方法。该模式实现了非阻塞 PDF 生成操作,并与 C# 的 async/await 关键字无缝集成。

如何并行处理多个 PDF 文件以提高性能?

IronPDF 支持使用 Task.WhenAll 等模式进行批量处理,以便并行执行多个 PDF 生成;支持 Parallel.ForEach 等模式,以便在 PDF 处理中使用多线程;还支持生产者-消费者模式,该模式带有用于大批量处理的通道。这些方法可优化资源使用并显著缩短总处理时间。

Chipego
软件工程师
Chipego 拥有倾听的天赋,帮助他理解客户问题,并提供智能解决方案。他于 2023 年加入 Iron Software 团队,学习了信息技术学士学位。IronPDF 和 IronOCR 是 Chipego 关注的两个产品,但由于他发现了支持客户的新方法,因此他的所有产品知识每天都在增长。他喜欢 Iron Software 的协作生活,公司各个成员利用他们的多样经验来贡献有效的创新解决方案。当 Chipego 离开办公桌时,他常常读书或踢足球。
准备开始了吗?
Nuget 下载 19,936,792 | 版本: 2026.7 刚刚发布
Still Scrolling Icon

还在滚动吗?

想快速获得证据? PM > Install-Package IronPdf
运行示例看着你的HTML代码变成PDF文件。