如何在 C# 中使用非同步與多執行緒生成 PDF 檔案
IronPDF 透過非同步操作與多執行緒技術,實現 C# 環境下的高效能 PDF 生成,相較於同步方法,在複雜的 HTML 渲染情境下,可將批次處理時間縮短多達 65%。
快速入門:使用 IronPDF 異步將 HTML 轉換為 PDF
只需幾行程式碼,即可開始使用 IronPDF 進行非同步 PDF 生成。
透過 RenderHtmlAsPdfAsync 方法,您可以高效地將 HTML 內容轉換為 PDF,從而優化應用程式的效能。 本指南說明如何運用非同步操作來生成高效能的 PDF 檔案,非常適合批次處理和多執行緒環境。
簡化工作流程(5 個步驟)
- 從 NuGet 下載 IronPDF,以實現非同步及多執行緒的 PDF 生成
- 準備待轉換的 HTML 內容
- 使用
RenderHtmlAsPdfAsync方法以非同步方式將 HTML 轉換為 PDF - 探索
Parallel.ForEachPDF 處理中的多執行緒方法 - 檢視不同 PDF 生成技術的效能比較
如何在 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);
批次處理有哪些常見模式?
批次處理 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
如何處理非同步 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
如何運用多執行緒來產生 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
我應該使用多少個並行執行緒?
最佳的並行執行緒數量取決於 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
哪些因素會影響 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 中的非同步方法可防止桌面應用程式中的使用者介面凍結,提升網頁應用程式的請求吞吐量,實現多核心處理器的資源更佳利用,並增強伺服器環境中的可擴展性。在處理複雜的 HTML 轉 PDF 轉換或同時處理多個 PDF 請求時,這些方法尤為有益。
該函式庫在 PDF 操作中採用何種非同步模式?
IronPDF 採用任務導向非同步模式 (TAP) 來實現其非同步操作,包括 RenderHtmlAsPdfAsync 等方法。此模式可實現非阻塞式的 PDF 生成操作,並能與 C# 的 async/await 關鍵字無縫整合。
如何並行處理多個 PDF 檔案以提升效能?
IronPDF 支援透過多種模式進行批次處理,例如使用 Task.WhenAll 並行執行多份 PDF 生成、使用 Parallel.ForEach 實現 PDF 處理的多執行緒,以及針對大型批次採用具通道的生產者-消費者模式。這些方法可優化資源使用效率,並顯著縮短總處理時間。

