How to Generate PDFs with Async & Multithreading in C#
IronPDF enables high-performance PDF generation in C# using async operations and multithreading, reducing batch processing time by up to 65% compared to synchronous methods for complex HTML rendering scenarios.
Quickstart: Convert HTML to PDF Asynchronously with IronPDF
Get started with asynchronous PDF generation using IronPDF in just a few lines of code.
With the RenderHtmlAsPdfAsync method, you can efficiently convert HTML content to PDF, optimizing your application's performance. This guide shows how to leverage async operations for high-performance PDF generation, ideal for batch processing and multi-threaded environments.
-
Install IronPDF with NuGet Package Manager
PM > Install-Package IronPdf -
Copy and run this code snippet.
var pdf = await IronPdf.ChromePdfRenderer.RenderHtmlAsPdfAsync("<h1>Hello World!</h1>"); -
Deploy to test on your live environment
Start using IronPDF in your project today with a free trial
Minimal Workflow (5 steps)
- Download IronPDF from NuGet for async and multithreading PDF generation
- Prepare the HTML contents to be converted
- Use the
RenderHtmlAsPdfAsyncmethod to convert HTML to PDF asynchronously - Explore the
Parallel.ForEachmethod for multithreading in PDF processing - Review the performance comparison of different PDF generation techniques
How Do I Implement Async PDF Generation in C#?
IronPDF fully supports async operations using rendering methods such as RenderHtmlAsPdfAsync. The async implementation in IronPDF leverages the Task-based Asynchronous Pattern (TAP) to enable non-blocking PDF generation operations. This approach benefits complex HTML content rendering or simultaneous PDF request processing. For full method reference, see the rendering methods documentation.
Asynchronous PDF generation prevents UI freezing in desktop applications and improves request throughput in web applications. Using async/await patterns allows your application to handle other operations while waiting for PDF rendering to complete, significantly enhancing responsiveness and user experience.
Why Should I Use Async Methods for PDF Generation?
Async methods provide key advantages for PDF generation workflows. They maintain application responsiveness during resource-intensive operations, enable better resource utilization on multi-core processors, and improve scalability in server environments. When handling complex HTML to PDF conversions, async operations prevent timeout issues and improve user experience.
: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);
What Are Common Patterns for Batch Processing?
Batch processing PDFs requires careful consideration of memory usage and performance. Effective patterns include using Task.WhenAll for parallel execution of multiple PDF generations, implementing producer-consumer patterns with channels for large batches, and utilizing parallel processing examples from the IronPDF documentation.
// 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
How Do I Handle Errors in Async PDF Operations?
Error handling in async PDF operations requires comprehensive exception management strategies. Use try-catch blocks within async methods, implement retry logic for transient failures, and consider using Polly for advanced retry policies. For detailed performance troubleshooting, IronPDF provides extensive logging capabilities.
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
How Can I Use Multi-Threading for PDF Generation?
IronPDF is thread-safe and supports multithreading when using the ChromePdfRenderer rendering engine. Note that multithreading is limited on macOS machines. The Chrome rendering engine provides excellent thread safety and performance characteristics for concurrent operations.
The Parallel.ForEach pattern works well for batch processing PDFs, allowing you to leverage all available CPU cores effectively. For comprehensive multi-threaded generation examples, refer to the IronPDF documentation.
When Should I Choose Multi-Threading Over Async?
Multi-threading is ideal for CPU-bound operations where you need to process multiple PDFs simultaneously with sufficient system resources. Choose multi-threading when processing large batches of PDFs on multi-core systems, when each PDF generation is independent, and when memory usage can be controlled. Async is better for I/O-bound operations and maintaining application responsiveness.
What Are the Thread-Safety Considerations?
IronPDF's ChromePdfRenderer is designed to be thread-safe, but certain considerations apply. Create separate renderer instances for each thread when using custom settings, avoid sharing PdfDocument instances between threads without synchronization, and monitor memory consumption when processing large documents concurrently. The installation overview provides additional details on configuring IronPDF for optimal thread safety.
// 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
How Many Concurrent Threads Should I Use?
The optimal number of concurrent threads depends on CPU cores, available memory, and PDF complexity. General guidelines include using Environment.ProcessorCount for CPU-bound operations, limiting to 2-4 threads for memory-intensive PDFs, and monitoring system resources to find the optimal configuration. The async examples demonstrate various threading strategies.
What Performance Improvements Can I Expect?
A comparison shows significant performance differences between rendering approaches. A 5-second delay is added in rendering with the WaitFor class for simulating complex HTML rendering. Below is a comparison table of performance using various techniques described above.
Why Does Async Perform Better Than Synchronous?
| Normal Render | Asynchronous Render | Multithreaded Render |
|---|---|---|
| 15.75 seconds | 05.59 seconds | 05.68 seconds |
Async operations excel because they allow efficient thread pool resource management, prevent main thread blocking, and enable better CPU utilization during I/O operations. The performance improvement comes from starting multiple rendering operations simultaneously rather than waiting for each to complete sequentially.
How Can I Measure Performance in My Application?
Measuring PDF generation performance requires proper benchmarking and monitoring. Use System.Diagnostics.Stopwatch for accurate timing measurements, implement custom performance counters for production monitoring, and leverage application insights or similar APM tools. Consider using the quickstart guide examples as a baseline for performance testing.
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
What Factors Affect PDF Generation Speed?
Several factors impact PDF generation performance. HTML complexity, including JavaScript execution and CSS rendering, directly affects processing time. External resource loading, such as images and fonts, can introduce delays. System resources like CPU, memory, and disk I/O play crucial roles. IronPDF configuration, including rendering options and engine settings, also influences speed. Understanding these factors helps optimize your PDF generation workflow for maximum efficiency.
For complex scenarios involving heavy JavaScript or delayed rendering, consider using WaitFor mechanisms to ensure complete page rendering before PDF generation. This approach guarantees accurate output while maintaining predictable performance characteristics.
Frequently Asked Questions
How much performance improvement can I expect with async PDF generation?
IronPDF's async operations and multithreading can reduce batch processing time by up to 65% compared to synchronous methods, particularly when rendering complex HTML content. The actual performance gain depends on factors like HTML complexity, system resources, and the number of concurrent operations.
What is the simplest way to convert HTML to PDF asynchronously?
The simplest way is using IronPDF's RenderHtmlAsPdfAsync method. With just one line of code: `var pdf = await IronPdf.ChromePdfRenderer.RenderHtmlAsPdfAsync("Hello World!");`, you can efficiently convert HTML content to PDF while maintaining application responsiveness.
Why should I use async methods instead of synchronous PDF generation?
Async methods in IronPDF prevent UI freezing in desktop applications, improve request throughput in web applications, enable better resource utilization on multi-core processors, and enhance scalability in server environments. They're particularly beneficial when handling complex HTML to PDF conversions or processing multiple PDF requests simultaneously.
What async pattern does the library use for PDF operations?
IronPDF implements the Task-based Asynchronous Pattern (TAP) for its async operations, including methods like RenderHtmlAsPdfAsync. This pattern enables non-blocking PDF generation operations and integrates seamlessly with C#'s async/await keywords.
How can I process multiple PDFs in parallel for better performance?
IronPDF supports batch processing using patterns like Task.WhenAll for parallel execution of multiple PDF generations, Parallel.ForEach for multithreading in PDF processing, and producer-consumer patterns with channels for large batches. These approaches optimize resource usage and significantly reduce total processing time.

