如何使用非同步和多執行緒生成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 中的非同步實作採用了基於任務的非同步模式 (TAP),以實現非阻塞式的 PDF 生成操作。 此方法適用於複雜的 HTML 內容渲染或同時處理 PDF 請求。 如需完整的方法參考,請參閱渲染方法文件

非同步 PDF 生成可防止桌面應用程式中的使用者介面凍結,並提升網頁應用程式的請求吞吐量。 透過使用 await 模式,您的應用程式可在等待 PDF 渲染完成期間處理其他操作,從而顯著提升系統反應速度與使用者體驗。

為何應使用非同步方法來生成 PDF?

非同步方法為 PDF 生成工作流程帶來關鍵優勢。 它們能在資源密集型操作期間維持應用程式的響應能力,提升多核心處理器的資源利用率,並改善伺服器環境中的可擴展性。 在處理複雜的 HTML 轉 PDF/A 轉換時,非同步操作可避免超時問題並提升使用者體驗。

: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 操作中進行錯誤處理,需要全面的例外管理策略。 請在非同步方法中使用 catch 區塊,針對暫時性錯誤實作重試邏輯,並考慮使用 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

Microsoft MVP

查看案例研究
Icon Quote related to 如何處理非同步 PDF 操作中的錯誤?

IronOCR意味著我們每年可以從手動處理中節省$40,000,同時提高生產力,釋放資源以進行高影響的任務。我會強烈推薦它。

Brent Matzelle related to 如何處理非同步 PDF 操作中的錯誤?

Brent Matzelle

首席技術官,OPYN

查看案例研究
Icon Quote related to 如何處理非同步 PDF 操作中的錯誤?

IronSuite在我們的運營中扮演著至關重要的角色。這些工具增加了包括建立平面圖和改善庫存管理在內的業務效率。

David Jones related to 如何處理非同步 PDF 操作中的錯誤?

David Jones

首席軟體工程師,Agorus Build

查看案例研究

如何運用多執行緒來產生 PDF 檔案?

IronPDF 具備執行緒安全性,並在使用 ChromePdfRenderer 渲染引擎時支援多執行緒。請注意,在 macOS 系統上,多執行緒功能受到限制。 Chrome 渲染引擎為並行操作提供了卓越的執行緒安全性與效能表現。

Parallel.ForEach 模式非常適合用於批次處理 PDF 檔案,讓您能有效運用所有可用的 CPU 核心。 如需完整的多執行緒生成範例,請參閱 IronPDF 文件。

何時該選擇多執行緒而非非同步?

多執行緒技術非常適合用於 CPU 密集型作業,當您需要同時處理多個 PDF 檔案且系統資源充足時,此技術是理想選擇。 在多核心系統上處理大量 PDF 檔案時,若每個 PDF 生成過程皆獨立運作,且能控制記憶體使用量,請選擇多執行緒處理。 對於 I/O 綁定操作以及維持應用程式的響應能力而言,非同步(Async)是更佳的選擇。

關於執行緒安全性的考量有哪些?

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 個,並監控系統資源以找出最佳配置。 這些非同步範例展示了各種執行緒策略。

我可以期待哪些效能提升?

比較結果顯示,各種渲染方法之間存在顯著的效能差異。 在渲染過程中,透過 WaitFor 類別加入 5 秒延遲,以模擬複雜的 HTML 渲染過程。 以下是採用上述各種技術所進行的效能比較表。

為什麼非同步的表現比同步更好?

正常顯示 非同步渲染 多執行緒渲染
15.75 秒 05.59 秒 05.68 秒

非同步操作之所以出色,在於它能實現高效執行緒池資源管理、防止主執行緒阻塞,並在 I/O 操作期間提升 CPU 利用率。 效能的提升源自於同時啟動多個渲染作業,而非等待每個作業依序完成。

我該如何衡量應用程式的效能?

要衡量 PDF 生成效能,必須進行適當的基準測試與監控。 請使用 System.Diagnostics.Stopwatch 進行精確的計時測量,實作自訂效能計數器以進行生產環境監控,並善用 Application Insights 或類似的 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/A 之前頁面已完全渲染。 此方法可確保輸出結果精準,同時維持可預測的效能特性。

常見問題

使用非同步PDF生成,我可以期望多少效能提升?

IronPDF的非同步操作和多執行緒能將批次處理時間較同步方法減少高達65%,特別是在渲染複雜HTML內容時。實際的效能提升取決於HTML的複雜性、系統資源和並發操作的數量等因素。

最簡單的非同步將HTML轉換成PDF的方法是什麼?

最簡單的方法是使用IronPDF的RenderHtmlAsPdfAsync方法。僅需一行程式碼:`var pdf = await IronPdf.ChromePdfRenderer.RenderHtmlAsPdfAsync('Hello World!');`,您就可以在保持應用程式響應性的同時有效將HTML內容轉換為PDF。

為什麼我應該使用非同步方法而不是同步PDF生成?

IronPDF的非同步方法防止桌面應用程式的UI凍結、提高Web應用程式的請求吞吐率、在多核心處理器上實現更好的資源利用率,並增強伺服器環境的可擴展性。它們在處理複雜的HTML到PDF轉換或同時處理多個PDF請求時尤其有用。

這個程式庫在PDF操作中使用哪種非同步模式?

IronPDF為其非同步操作實現了基於任務的非同步模式(TAP),包括像RenderHtmlAsPdfAsync這樣的方法。此模式使非阻塞的PDF生成操作成為可能,並能無縫整合C#的async/await關鍵字。

我該如何並行處理多個PDF以獲得更好的效能?

IronPDF支持使用像Task.WhenAll這樣的模式進行批次處理以並行執行多個PDF生成,使用Parallel.ForEach進行PDF處理的多執行緒運行,以及對於大型批次使用通道的生產者-消費者模式。這些方法優化了資源使用並顯著減少總處理時間。

Chipego
軟體工程師
Chipego擅於傾聽,幫助他理解客戶問題,並提供明智的解決方案。他在2023年加入Iron Software團隊,之前學習了資訊技術學士學位。Chipego專注於IronPDF和IronOCR這兩種產品,但他的產品知識每天都在增長,因為他找到支援客戶的新方法。他喜歡Iron Software的合作生活,公司內的團隊成員帶來他們的多樣化經驗,貢獻出有效且創新的解決方案。當Chipego不在辦公桌前時,他常常在讀好書或踢足球。
準備開始了嗎?
Nuget 下載 20,296,129 | 版本: 2026.7 剛剛發布
Still Scrolling Icon

還在捲動嗎?

想快速獲得證明嗎? PM > Install-Package IronPdf
執行範例 看您的HTML變成PDF。