비동기 및 멀티스레딩을 사용하여 PDF를 생성하는 방법

C#에서 비동기 및 멀티스레딩으로 PDF 만들기 — 고성능 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 생성은 데스크톱 애플리케이션에서 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 파일을 일괄 처리할 때는 메모리 사용량과 성능을 신중하게 고려해야 합니다. 효과적인 패턴으로는 여러 PDF 생성을 병렬 실행하는 Task.WhenAll 사용, 대량 배치를 위한 채널을 사용한 생산자-소비자 패턴 구현, 그리고 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 작업에서 오류를 처리하려면 포괄적인 예외 관리 전략이 필요합니다. 비동기 메서드 내에서 try-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

PDF 생성에 멀티스레딩을 어떻게 사용할 수 있나요?

IronPDF는 스레드 안전성이 있으며 ChromePdfRenderer 렌더링 엔진을 사용할 때 다중 스레드를 지원합니다. macOS 기기에서는 다중 스레드 사용이 제한적입니다. Chrome 렌더링 엔진은 동시 작업에 대해 탁월한 스레드 안전성과 성능 특성을 제공합니다.

The Parallel.ForEach pattern works well for batch processing PDFs, allowing you to leverage all available CPU cores effectively. 멀티스레드 생성에 대한 자세한 예제 는 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개의 스레드로 제한, 시스템 리소스를 모니터링하여 최적의 설정을 찾는 것이 포함됩니다. 비동기 예제는 다양한 스레딩 전략을 보여줍니다.

어떤 성능 향상을 기대할 수 있을까요?

비교 결과 렌더링 방식 간에 성능 차이가 상당히 큰 것으로 나타났습니다. 복잡한 HTML 렌더링을 시뮬레이션하기 위해 WaitFor 클래스를 사용하여 렌더링에 5초의 지연 시간을 추가합니다. 아래는 위에서 설명한 다양한 기법을 사용했을 때의 성능 비교표입니다.

비동기 방식이 동기 방식보다 성능이 더 좋은 이유는 무엇일까요?

일반 렌더링 비동기 렌더링 멀티스레드 렌더링
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 생성 성능에 영향을 미치는 요인은 여러 가지가 있습니다. JavaScript 실행 및 CSS 렌더링을 포함한 HTML의 복잡성은 처리 시간에 직접적인 영향을 미칩니다. 이미지 및 글꼴과 같은 외부 리소스 로딩 또한 지연을 유발할 수 있습니다. CPU, 메모리, 디스크 I/O와 같은 시스템 리소스는 매우 중요한 역할을 합니다. 렌더링 옵션 및 엔진 설정을 포함한 IronPDF 구성도 속도에 영향을 미칩니다. 이러한 요소들을 이해하면 PDF 생성 워크플로를 최적화하여 효율성을 극대화할 수 있습니다.

JavaScript 사용량이 많거나 렌더링이 지연되는 복잡한 시나리오의 경우, PDF 생성 전에 페이지 렌더링이 완료되도록 WaitFor 메커니즘을 사용하는 것을 고려하십시오. 이 접근 방식은 예측 가능한 성능 특성을 유지하면서 정확한 출력을 보장합니다.

자주 묻는 질문

비동기 PDF 생성을 통해 성능 향상을 어느 정도 기대할 수 있을까요?

IronPDF의 비동기 작업 및 멀티스레딩은 특히 복잡한 HTML 콘텐츠를 렌더링할 때 동기 방식에 비해 일괄 처리 시간을 최대 65%까지 단축할 수 있습니다. 실제 성능 향상 폭은 HTML 복잡성, 시스템 리소스, 동시 작업 수 등의 요소에 따라 달라집니다.

HTML을 PDF로 비동기적으로 변환하는 가장 간단한 방법은 무엇입니까?

가장 간단한 방법은 IronPDF의 RenderHtmlAsPdfAsync 메서드를 사용하는 것입니다. `var pdf = await IronPDF.ChromePdfRenderer.RenderHtmlAsPdfAsync("Hello World!");` 단 한 줄의 코드로 애플리케이션 응답성을 유지하면서 HTML 콘텐츠를 효율적으로 PDF로 변환할 수 있습니다.

PDF 생성 시 동기식 방식 대신 비동기식 방식을 사용해야 하는 이유는 무엇인가요?

IronPDF의 비동기 메서드는 데스크톱 애플리케이션에서 UI 멈춤 현상을 방지하고, 웹 애플리케이션에서 요청 처리량을 향상시키며, 멀티코어 프로세서에서 리소스 활용도를 높이고, 서버 환경에서 확장성을 강화합니다. 특히 복잡한 HTML을 PDF로 변환하거나 여러 PDF 요청을 동시에 처리할 때 유용합니다.

이 라이브러리는 PDF 작업에 어떤 비동기 패턴을 사용하나요?

IronPDF는 RenderHtmlAsPdfAsync와 같은 메서드를 포함한 비동기 작업에 대해 TAP(Task-based Asynchronous Pattern)를 구현합니다. 이 패턴을 통해 PDF 생성 작업을 비차단 방식으로 수행할 수 있으며, C#의 async/await 키워드와 원활하게 통합됩니다.

성능 향상을 위해 여러 PDF 파일을 병렬로 처리하려면 어떻게 해야 할까요?

IronPDF는 Task.WhenAll과 같은 패턴을 사용하여 여러 PDF 생성 작업을 병렬로 실행하거나, Parallel.ForEach를 사용하여 PDF 처리를 멀티스레딩으로 수행하거나, 채널을 활용한 생산자-소비자 패턴을 사용하여 대규모 배치 처리를 지원합니다. 이러한 접근 방식은 리소스 사용을 최적화하고 전체 처리 시간을 크게 단축합니다.

치페고
소프트웨어 엔지니어
치페고는 경청 능력이 뛰어나 고객의 문제를 정확히 파악하고 지능적인 해결책을 제시합니다. 정보 기술 학사 학위를 취득한 후 2023년에 Iron Software 팀에 합류했습니다. IronPDF와 IronOCR은 치페고가 주로 담당하는 제품이지만, 고객 지원 방법을 끊임없이 연구하며 모든 제품에 대한 지식을 넓혀가고 있습니다. 그는 Iron Software의 협업적인 분위기를 좋아하며, 회사 전반의 다양한 경험을 가진 팀원들이 효과적이고 혁신적인 솔루션 개발에 기여하는 점을 높이 평가합니다. 치페고는 업무 외 시간에는 독서를 즐기거나 축구를 하는 것을 좋아합니다.
시작할 준비 되셨나요?
Nuget 다운로드 18,318,263 | 버전: 2026.4 방금 출시되었습니다
Still Scrolling Icon

아직도 스크롤하고 계신가요?

빠른 증거를 원하시나요? PM > Install-Package IronPdf
샘플을 실행하세요 HTML이 PDF로 변환되는 것을 지켜보세요.