透かしなしで本番環境でテストしてください。
必要な場所で動作します。
30日間、完全に機能する製品をご利用いただけます。
数分で稼働させることができます。
製品トライアル期間中にサポートエンジニアリングチームへの完全アクセス
並行性管理は、C#の高性能アプリケーションの重要な側面です。 潜在的な競合やパフォーマンスのボトルネックを回避しながら、リソースを効率的に利用することを保証するため、軽量なセマフォがアクセスを制御することは非常に役立ちます。 これはSemaphoreSlimの出番です。 SemaphoreSlimは軽量な同期プリミティブで、リソースへのアクセスを制御し、最終的に競合状態を防いでスレッドの安全性を確保します。
では、これをPDF生成プロセスを管理するPDFライブラリと一緒に実装したいとしたらどうでしょう? 強力なPDFライブラリをお探しなら、IronPDFがあります。 IronPDFは.NET開発者のための堅牢なPDF生成・操作ライブラリで、マルチスレッド環境で使用される場合、並行性管理から大きな恩恵を受けることができます。
SemaphoreSlimとIronPDFが実際に動作しているところをご覧になりたい場合は、SemaphoreSlimを使用する利点と、並行処理を安全に処理し、パフォーマンスを向上させ、信頼できるPDF処理を保証するためにIronPDFと統合する方法を探りますので、ぜひお読みください。
SemaphoreSlimは、.NETの同期プリミティブで、特定のリソースまたはリソースプールに同時にアクセスできるスレッド数を制限します。 これは完全なSemaphoreクラスの軽量版であり、よりシンプルで高速なセマフォで十分な状況で、より効率的に動作するように設計されています。
SemaphoreSlimを使用する利点の一部は、Semaphoreと比較してシステムのオーバーヘッドが削減され、限られたリソース(データベース接続やファイルアクセスなど)の管理に理想的であり、非同期の待機メソッドをサポートしているため、現代のasync/awaitプログラミングパターンに非常に適していることです。
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
// Semaphore count
private static SemaphoreSlim _semaphore = new SemaphoreSlim(3); // Limit to 3 concurrent threads.
static async Task Main(string[] args)
{
// Start tasks that will wait on the semaphore.
var tasks = new Task[5];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = Task.Run(() => AccessResource(i));
}
// Simulate some work in the main thread (e.g., initialization).
Console.WriteLine("Main thread is preparing resources...");
await Task.Delay(2000); // Simulate initialization delay.
// Main thread calls release, releases semaphore permits to allow waiting tasks to proceed.
Console.WriteLine("Main thread releasing semaphore permits...");
_semaphore.Release(2); // Releases 2 permits, allowing up to 2 tasks to proceed.
// Wait for all tasks to complete.
await Task.WhenAll(tasks);
Console.WriteLine("All tasks completed.");
}
static async Task AccessResource(int id)
{
Console.WriteLine($"Task {id} waiting to enter...");
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"Current thread successfully entered by Task {id}.");
await Task.Delay(1000); // Simulate work.
}
finally
{
Console.WriteLine($"Task {id} releasing.");
_semaphore.Release();
}
}
}
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
// Semaphore count
private static SemaphoreSlim _semaphore = new SemaphoreSlim(3); // Limit to 3 concurrent threads.
static async Task Main(string[] args)
{
// Start tasks that will wait on the semaphore.
var tasks = new Task[5];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = Task.Run(() => AccessResource(i));
}
// Simulate some work in the main thread (e.g., initialization).
Console.WriteLine("Main thread is preparing resources...");
await Task.Delay(2000); // Simulate initialization delay.
// Main thread calls release, releases semaphore permits to allow waiting tasks to proceed.
Console.WriteLine("Main thread releasing semaphore permits...");
_semaphore.Release(2); // Releases 2 permits, allowing up to 2 tasks to proceed.
// Wait for all tasks to complete.
await Task.WhenAll(tasks);
Console.WriteLine("All tasks completed.");
}
static async Task AccessResource(int id)
{
Console.WriteLine($"Task {id} waiting to enter...");
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"Current thread successfully entered by Task {id}.");
await Task.Delay(1000); // Simulate work.
}
finally
{
Console.WriteLine($"Task {id} releasing.");
_semaphore.Release();
}
}
}
Imports System
Imports System.Threading
Imports System.Threading.Tasks
Friend Class Program
' Semaphore count
Private Shared _semaphore As New SemaphoreSlim(3) ' Limit to 3 concurrent threads.
Shared Async Function Main(ByVal args() As String) As Task
' Start tasks that will wait on the semaphore.
Dim tasks = New Task(4){}
For i As Integer = 0 To tasks.Length - 1
tasks(i) = Task.Run(Function() AccessResource(i))
Next i
' Simulate some work in the main thread (e.g., initialization).
Console.WriteLine("Main thread is preparing resources...")
Await Task.Delay(2000) ' Simulate initialization delay.
' Main thread calls release, releases semaphore permits to allow waiting tasks to proceed.
Console.WriteLine("Main thread releasing semaphore permits...")
_semaphore.Release(2) ' Releases 2 permits, allowing up to 2 tasks to proceed.
' Wait for all tasks to complete.
Await Task.WhenAll(tasks)
Console.WriteLine("All tasks completed.")
End Function
Private Shared Async Function AccessResource(ByVal id As Integer) As Task
Console.WriteLine($"Task {id} waiting to enter...")
Await _semaphore.WaitAsync()
Try
Console.WriteLine($"Current thread successfully entered by Task {id}.")
Await Task.Delay(1000) ' Simulate work.
Finally
Console.WriteLine($"Task {id} releasing.")
_semaphore.Release()
End Try
End Function
End Class
プログラムの動作中、利用可能なパーミッションがすべてスレッドによって取得されると、セマフォのカウントは動的にゼロスレッドになることがあります。 この状態は、許可された最大同時アクセス数に達したことを示します。
必要であれば、最初と最大のスレッド数を設定し、初期セマフォカウントをゼロに設定してから、リソースが準備完了したときにセマフォカウントを増やす別の初期化タスクを使用して選択したスレッド数を進めるようにすることができます。 セマフォカウントがゼロのとき、スレッドはセマフォに入ろうとするときに待機します。これを「ブロック待ち」と呼びます。
前のセマフォカウントを追跡して、セマフォの動作を前のカウントに基づいて調整することができます。 その後、セマフォを適切に操作することができます(例:解放または待機する)。 スレッドが解放されると、セマフォ・カウントが減少します。
SemaphoreSlimの一般的な使用例は以下のとおりです:
IronPDF をマルチスレッド環境で使用開始するには、IronPDF NuGet パッケージをインストールしてください。 ツール > NuGet パッケージ マネージャー > ソリューション用 NuGet パッケージ マネージャーを開き、IronPDF を検索して行うことができます。
または、パッケージマネージャーコンソールで次のコマンドを実行します。
Install-Package IronPdf
コードでIronPDFを使用し始めるには、コードファイルの先頭にusing IronPdf
文を配置していることを確認してください。IronPDFを環境にセットアップするための詳細なガイドについては、使用開始ページをご覧ください。
SemaphoreSlimを使用すると、PDF生成タスクへのアクセスを効果的に制御できます。 これにより、アプリケーションが同時に多くのPDFを生成しようとして、パフォーマンスに影響を与えたり、障害を引き起こしたりしないようにします。
次のコード例は、SemaphoreSlimとIronPDFの基本的な使い方を示しています。
using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
private static SemaphoreSlim _semaphore = new SemaphoreSlim(2); // Limit to 2 concurrent threads.
static async Task Main(string[] args)
{
var tasks = new Task[5];
for (int i = 0; i < tasks.Length; i++)
{
string htmlContent = $"<h1>PDF Document {i}</h1><p>This is a sample PDF content for task {i}.</p>";
string outputPath = $"output_{i}.pdf";
// Start multiple tasks to demonstrate controlled concurrency.
tasks[i] = GeneratePdfAsync(htmlContent, outputPath, i);
}
await Task.WhenAll(tasks);
}
static async Task GeneratePdfAsync(string htmlContent, string outputPath, int taskId)
{
Console.WriteLine($"Task {taskId} is waiting for access...");
// Wait to enter the semaphore.
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"Task {taskId} has started PDF generation.");
ChromePdfRenderer renderer = new ChromePdfRenderer();
PdfDocument pdf = await renderer.RenderHtmlAsPdfAsync(htmlContent);
pdf.SaveAs(outputPath);
Console.WriteLine($"Task {taskId} has completed PDF generation.");
}
finally
{
// Ensure semaphore is released to allow other tasks to proceed.
_semaphore.Release();
Console.WriteLine($"Task {taskId} has released semaphore.");
}
}
}
using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
private static SemaphoreSlim _semaphore = new SemaphoreSlim(2); // Limit to 2 concurrent threads.
static async Task Main(string[] args)
{
var tasks = new Task[5];
for (int i = 0; i < tasks.Length; i++)
{
string htmlContent = $"<h1>PDF Document {i}</h1><p>This is a sample PDF content for task {i}.</p>";
string outputPath = $"output_{i}.pdf";
// Start multiple tasks to demonstrate controlled concurrency.
tasks[i] = GeneratePdfAsync(htmlContent, outputPath, i);
}
await Task.WhenAll(tasks);
}
static async Task GeneratePdfAsync(string htmlContent, string outputPath, int taskId)
{
Console.WriteLine($"Task {taskId} is waiting for access...");
// Wait to enter the semaphore.
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"Task {taskId} has started PDF generation.");
ChromePdfRenderer renderer = new ChromePdfRenderer();
PdfDocument pdf = await renderer.RenderHtmlAsPdfAsync(htmlContent);
pdf.SaveAs(outputPath);
Console.WriteLine($"Task {taskId} has completed PDF generation.");
}
finally
{
// Ensure semaphore is released to allow other tasks to proceed.
_semaphore.Release();
Console.WriteLine($"Task {taskId} has released semaphore.");
}
}
}
Imports IronPdf
Imports System
Imports System.Threading
Imports System.Threading.Tasks
Friend Class Program
Private Shared _semaphore As New SemaphoreSlim(2) ' Limit to 2 concurrent threads.
Shared Async Function Main(ByVal args() As String) As Task
Dim tasks = New Task(4){}
For i As Integer = 0 To tasks.Length - 1
Dim htmlContent As String = $"<h1>PDF Document {i}</h1><p>This is a sample PDF content for task {i}.</p>"
Dim outputPath As String = $"output_{i}.pdf"
' Start multiple tasks to demonstrate controlled concurrency.
tasks(i) = GeneratePdfAsync(htmlContent, outputPath, i)
Next i
Await Task.WhenAll(tasks)
End Function
Private Shared Async Function GeneratePdfAsync(ByVal htmlContent As String, ByVal outputPath As String, ByVal taskId As Integer) As Task
Console.WriteLine($"Task {taskId} is waiting for access...")
' Wait to enter the semaphore.
Await _semaphore.WaitAsync()
Try
Console.WriteLine($"Task {taskId} has started PDF generation.")
Dim renderer As New ChromePdfRenderer()
Dim pdf As PdfDocument = Await renderer.RenderHtmlAsPdfAsync(htmlContent)
pdf.SaveAs(outputPath)
Console.WriteLine($"Task {taskId} has completed PDF generation.")
Finally
' Ensure semaphore is released to allow other tasks to proceed.
_semaphore.Release()
Console.WriteLine($"Task {taskId} has released semaphore.")
End Try
End Function
End Class
この例では、まずSemaphoreSlimを初期化し、SemaphoreSlimの初期カウントと最大カウントを'2'に設定し、同時PDF生成を2回に制限しています。 次に、プログラムが行うべきタスクの数を制御するために使用されるタスク配列を作成し、その後、タスク配列内のタスクの数に基づいて動的にPDFを作成するためにforループを使用します。
WaitAsync()
メソッドはセマフォに入るために使用され、その後、例外が発生しても常にセマフォが解放されるようにするために、finallyブロックでRelease()
が使用されます。 コンソール出力ログは、各タスクがいつ開始し、いつ終了し、セマフォを解放したかを示し、これにより並行動作の追跡が可能になります。
スレッドセーフは、複数のスレッドが共有リソースとやり取りする際に非常に重要です。 PDF操作において、SemaphoreSlimは定義された数のスレッドのみが同時にPDFを変更できるようにし、競合状態を防ぎ、一貫性を確保します。 以下のコードでは、一度に1つの操作しか起こらないようにしながら、複数のPDFに透かしを追加するシナリオをシミュレートしています。
using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
private static SemaphoreSlim _semaphore = new SemaphoreSlim(1);
static async Task Main(string[] args)
{
// Setting array of tasks
var tasks = new Task[3];
for (int i = 0; i < tasks.Length; i++)
{
string inputPath = $"input_{i}.pdf"; // Input PDF file path
string outputPath = $"output_{i}.pdf"; // Output PDF file path
string watermarkText = @"
<img src='https://ironsoftware.com/img/products/ironpdf-logo-text-dotnet.svg'>
<h1>Iron Software</h1>";
// Start multiple tasks to add watermarks concurrently.
tasks[i] = AddWatermarkAsync(inputPath, outputPath, watermarkText, i);
}
await Task.WhenAll(tasks); // Wait for all tasks to finish.
}
static async Task AddWatermarkAsync(string input, string outputPath, string watermark, int taskId)
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} is waiting to add a watermark...");
// Wait to enter the semaphore.
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} is adding a watermark.");
var pdf = PdfDocument.FromFile(input);
pdf.ApplyWatermark(watermark); // Add watermark
pdf.SaveAs(outputPath); // Save the modified PDF
Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} has completed watermarking.");
}
finally
{
// Release the semaphore after the task is done.
_semaphore.Release();
Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} has released semaphore.");
}
}
}
using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
private static SemaphoreSlim _semaphore = new SemaphoreSlim(1);
static async Task Main(string[] args)
{
// Setting array of tasks
var tasks = new Task[3];
for (int i = 0; i < tasks.Length; i++)
{
string inputPath = $"input_{i}.pdf"; // Input PDF file path
string outputPath = $"output_{i}.pdf"; // Output PDF file path
string watermarkText = @"
<img src='https://ironsoftware.com/img/products/ironpdf-logo-text-dotnet.svg'>
<h1>Iron Software</h1>";
// Start multiple tasks to add watermarks concurrently.
tasks[i] = AddWatermarkAsync(inputPath, outputPath, watermarkText, i);
}
await Task.WhenAll(tasks); // Wait for all tasks to finish.
}
static async Task AddWatermarkAsync(string input, string outputPath, string watermark, int taskId)
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} is waiting to add a watermark...");
// Wait to enter the semaphore.
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} is adding a watermark.");
var pdf = PdfDocument.FromFile(input);
pdf.ApplyWatermark(watermark); // Add watermark
pdf.SaveAs(outputPath); // Save the modified PDF
Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} has completed watermarking.");
}
finally
{
// Release the semaphore after the task is done.
_semaphore.Release();
Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} has released semaphore.");
}
}
}
Imports IronPdf
Imports System
Imports System.Threading
Imports System.Threading.Tasks
Friend Class Program
Private Shared _semaphore As New SemaphoreSlim(1)
Shared Async Function Main(ByVal args() As String) As Task
' Setting array of tasks
Dim tasks = New Task(2){}
For i As Integer = 0 To tasks.Length - 1
Dim inputPath As String = $"input_{i}.pdf" ' Input PDF file path
Dim outputPath As String = $"output_{i}.pdf" ' Output PDF file path
Dim watermarkText As String = "
<img src='https://ironsoftware.com/img/products/ironpdf-logo-text-dotnet.svg'>
<h1>Iron Software</h1>"
' Start multiple tasks to add watermarks concurrently.
tasks(i) = AddWatermarkAsync(inputPath, outputPath, watermarkText, i)
Next i
Await Task.WhenAll(tasks) ' Wait for all tasks to finish.
End Function
Private Shared Async Function AddWatermarkAsync(ByVal input As String, ByVal outputPath As String, ByVal watermark As String, ByVal taskId As Integer) As Task
Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} is waiting to add a watermark...")
' Wait to enter the semaphore.
Await _semaphore.WaitAsync()
Try
Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} is adding a watermark.")
Dim pdf = PdfDocument.FromFile(input)
pdf.ApplyWatermark(watermark) ' Add watermark
pdf.SaveAs(outputPath) ' Save the modified PDF
Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} has completed watermarking.")
Finally
' Release the semaphore after the task is done.
_semaphore.Release()
Console.WriteLine($"{DateTime.Now:HH:mm:ss} - Task {taskId} has released semaphore.")
End Try
End Function
End Class
private static SemaphoreSlim _semaphore = new SemaphoreSlim(1);
を使用してセマフォカウントを1に設定することで、一度に1つのタスクのみがPDFを操作できるようにします。
IronPDFは大きなHTMLファイルをPDFに変換するようなリソース集約的なタスクを処理し、非同期環境でこれらのタスクを実行することに優れています。 SemaphoreSlimを使用してこれらの操作を管理することで、高負荷時でもパフォーマンスを低下させることなくアプリケーションの応答性を維持することができます。
次のコード例は、システムリソースに過負荷をかけないように、同時に行われる大きなHTMLからPDFへの変換の数を制限する必要があるシナリオを示しています。
using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
// Limit concurrent large PDF conversions to 2.
private static SemaphoreSlim _semaphore = new SemaphoreSlim(2);
static async Task Main(string[] args)
{
var tasks = new Task[4];
for (int i = 0; i < tasks.Length; i++)
{
string htmlContent = $"<h1>Large Document {i}</h1><p>Content for a large HTML file {i}.</p>";
string outputPath = $"large_output_{i}.pdf";
// Start multiple tasks to convert large HTML files to PDFs.
tasks[i] = ConvertLargeHtmlAsync(htmlContent, outputPath, i);
}
await Task.WhenAll(tasks); // Wait for all tasks to finish.
}
// Method to convert large HTML to PDF using SemaphoreSlim to control resource usage.
public static async Task ConvertLargeHtmlAsync(string htmlContent, string outputPath, int taskId)
{
Console.WriteLine($"Task {taskId} is waiting to start conversion...");
// Wait to enter the semaphore.
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"Task {taskId} is converting large HTML to PDF.");
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(htmlContent); // Convert large HTML to PDF
pdf.SaveAs(outputPath); // Save the PDF file
Console.WriteLine($"Task {taskId} has completed conversion.");
}
finally
{
// Ensure the semaphore is released to allow other tasks to proceed.
_semaphore.Release();
Console.WriteLine($"Task {taskId} has released semaphore.");
}
}
}
using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
// Limit concurrent large PDF conversions to 2.
private static SemaphoreSlim _semaphore = new SemaphoreSlim(2);
static async Task Main(string[] args)
{
var tasks = new Task[4];
for (int i = 0; i < tasks.Length; i++)
{
string htmlContent = $"<h1>Large Document {i}</h1><p>Content for a large HTML file {i}.</p>";
string outputPath = $"large_output_{i}.pdf";
// Start multiple tasks to convert large HTML files to PDFs.
tasks[i] = ConvertLargeHtmlAsync(htmlContent, outputPath, i);
}
await Task.WhenAll(tasks); // Wait for all tasks to finish.
}
// Method to convert large HTML to PDF using SemaphoreSlim to control resource usage.
public static async Task ConvertLargeHtmlAsync(string htmlContent, string outputPath, int taskId)
{
Console.WriteLine($"Task {taskId} is waiting to start conversion...");
// Wait to enter the semaphore.
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"Task {taskId} is converting large HTML to PDF.");
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(htmlContent); // Convert large HTML to PDF
pdf.SaveAs(outputPath); // Save the PDF file
Console.WriteLine($"Task {taskId} has completed conversion.");
}
finally
{
// Ensure the semaphore is released to allow other tasks to proceed.
_semaphore.Release();
Console.WriteLine($"Task {taskId} has released semaphore.");
}
}
}
Imports IronPdf
Imports System
Imports System.Threading
Imports System.Threading.Tasks
Friend Class Program
' Limit concurrent large PDF conversions to 2.
Private Shared _semaphore As New SemaphoreSlim(2)
Shared Async Function Main(ByVal args() As String) As Task
Dim tasks = New Task(3){}
For i As Integer = 0 To tasks.Length - 1
Dim htmlContent As String = $"<h1>Large Document {i}</h1><p>Content for a large HTML file {i}.</p>"
Dim outputPath As String = $"large_output_{i}.pdf"
' Start multiple tasks to convert large HTML files to PDFs.
tasks(i) = ConvertLargeHtmlAsync(htmlContent, outputPath, i)
Next i
Await Task.WhenAll(tasks) ' Wait for all tasks to finish.
End Function
' Method to convert large HTML to PDF using SemaphoreSlim to control resource usage.
Public Shared Async Function ConvertLargeHtmlAsync(ByVal htmlContent As String, ByVal outputPath As String, ByVal taskId As Integer) As Task
Console.WriteLine($"Task {taskId} is waiting to start conversion...")
' Wait to enter the semaphore.
Await _semaphore.WaitAsync()
Try
Console.WriteLine($"Task {taskId} is converting large HTML to PDF.")
Dim renderer = New ChromePdfRenderer()
Dim pdf = Await renderer.RenderHtmlAsPdfAsync(htmlContent) ' Convert large HTML to PDF
pdf.SaveAs(outputPath) ' Save the PDF file
Console.WriteLine($"Task {taskId} has completed conversion.")
Finally
' Ensure the semaphore is released to allow other tasks to proceed.
_semaphore.Release()
Console.WriteLine($"Task {taskId} has released semaphore.")
End Try
End Function
End Class
大きなHTMLファイルをPDFに変換するようなリソースを大量に必要とするタスクでは、SemaphoreSlimが負荷のバランスをとり、リソースの使用を最適化します。 同時処理の上限を2つに設定することで、リソース集約的なPDF生成タスクによってシステムが圧倒されるのを防ぎます。 このアプローチにより、作業負荷が均等に分散され、アプリケーション全体のパフォーマンスと安定性が向上します。
セマフォが正しく解放されないと、デッドロックが発生する可能性があります。 留意すべき良い習慣は、例外が発生してもセマフォが解放されるようにtry-finallyブロックを使用することです。 デッドロックを避けるためのベストプラクティスとして、必ずfinallyブロックでセマフォを解放することや、非同期コード内でWait()
やResult
のようなブロッキング呼び出しを使用しないことを覚えておいてください。
using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
private static SemaphoreSlim _semaphore = new SemaphoreSlim(3);
static async Task Main(string[] args)
{
var tasks = new Task[3];
for (int i = 0; i < tasks.Length; i++)
{
string content = $"<h1>Document {i}</h1><p>Content for PDF {i}.</p>";
string path = $"safe_output_{i}.pdf";
// Start multiple tasks to demonstrate deadlock-free semaphore usage.
tasks[i] = SafePdfTaskAsync(content, path, i);
}
await Task.WhenAll(tasks); // Wait for all tasks to finish.
}
// Method demonstrating best practices for using SemaphoreSlim to avoid deadlocks.
public static async Task SafePdfTaskAsync(string content, string path, int taskId)
{
Console.WriteLine($"Task {taskId} is waiting to generate PDF...");
// Wait to enter the semaphore.
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"Task {taskId} is generating PDF.");
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(content); // Render HTML to PDF
pdf.SaveAs(path); // Save the PDF
Console.WriteLine($"Task {taskId} has completed PDF generation.");
}
catch (Exception ex)
{
Console.WriteLine($"Task {taskId} encountered an error: {ex.Message}");
}
finally
{
// Always release the semaphore, even if an error occurs.
_semaphore.Release();
Console.WriteLine($"Task {taskId} has released semaphore.");
}
}
}
using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
private static SemaphoreSlim _semaphore = new SemaphoreSlim(3);
static async Task Main(string[] args)
{
var tasks = new Task[3];
for (int i = 0; i < tasks.Length; i++)
{
string content = $"<h1>Document {i}</h1><p>Content for PDF {i}.</p>";
string path = $"safe_output_{i}.pdf";
// Start multiple tasks to demonstrate deadlock-free semaphore usage.
tasks[i] = SafePdfTaskAsync(content, path, i);
}
await Task.WhenAll(tasks); // Wait for all tasks to finish.
}
// Method demonstrating best practices for using SemaphoreSlim to avoid deadlocks.
public static async Task SafePdfTaskAsync(string content, string path, int taskId)
{
Console.WriteLine($"Task {taskId} is waiting to generate PDF...");
// Wait to enter the semaphore.
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"Task {taskId} is generating PDF.");
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(content); // Render HTML to PDF
pdf.SaveAs(path); // Save the PDF
Console.WriteLine($"Task {taskId} has completed PDF generation.");
}
catch (Exception ex)
{
Console.WriteLine($"Task {taskId} encountered an error: {ex.Message}");
}
finally
{
// Always release the semaphore, even if an error occurs.
_semaphore.Release();
Console.WriteLine($"Task {taskId} has released semaphore.");
}
}
}
Imports IronPdf
Imports System
Imports System.Threading
Imports System.Threading.Tasks
Friend Class Program
Private Shared _semaphore As New SemaphoreSlim(3)
Shared Async Function Main(ByVal args() As String) As Task
Dim tasks = New Task(2){}
For i As Integer = 0 To tasks.Length - 1
Dim content As String = $"<h1>Document {i}</h1><p>Content for PDF {i}.</p>"
Dim path As String = $"safe_output_{i}.pdf"
' Start multiple tasks to demonstrate deadlock-free semaphore usage.
tasks(i) = SafePdfTaskAsync(content, path, i)
Next i
Await Task.WhenAll(tasks) ' Wait for all tasks to finish.
End Function
' Method demonstrating best practices for using SemaphoreSlim to avoid deadlocks.
Public Shared Async Function SafePdfTaskAsync(ByVal content As String, ByVal path As String, ByVal taskId As Integer) As Task
Console.WriteLine($"Task {taskId} is waiting to generate PDF...")
' Wait to enter the semaphore.
Await _semaphore.WaitAsync()
Try
Console.WriteLine($"Task {taskId} is generating PDF.")
Dim renderer = New ChromePdfRenderer()
Dim pdf = Await renderer.RenderHtmlAsPdfAsync(content) ' Render HTML to PDF
pdf.SaveAs(path) ' Save the PDF
Console.WriteLine($"Task {taskId} has completed PDF generation.")
Catch ex As Exception
Console.WriteLine($"Task {taskId} encountered an error: {ex.Message}")
Finally
' Always release the semaphore, even if an error occurs.
_semaphore.Release()
Console.WriteLine($"Task {taskId} has released semaphore.")
End Try
End Function
End Class
try-catch-finally
ブロックを使用することで、例外がスローされても SemaphoreSlim オブジェクトが常に解放されることが保証され、デッドロックを防ぐことができます。 エラーをログに記録し、セマフォの解放を適切に管理することで、プログラムを安定させ、予期せぬ動作を防ぐことができます。
下の出力画像でわかるように、存在しないHTMLファイルをプログラムに読み込ませようとしてエラーをシミュレートしましたが、このエラーでも、プログラムは何が間違っていたかを教えてくれるエラーメッセージを表示し、finallyブロックを使ってセマフォの解放に進みます。
IronPDFは同時PDF処理タスクを効率的に処理するように設計されており、他の多くのPDFライブラリよりも優れたパフォーマンスと信頼性を提供します。 堅牢なアーキテクチャにより、アプリケーションのニーズに合わせて拡張できるため、需要の高い環境に最適です。 パフォーマンス、使いやすさ、堅牢性の基準で他のPDFライブラリと比較した場合、IronPDF は強力な競争相手であることが証明されています。 これを紹介するために、私はIronPDFをiTextSharp, PDFsharp, DinkToPdf, EvoPDFのような他の人気のあるPDFライブラリと比較しました:
IronPDF:
非同期操作: 非同期のPDF生成をサポートし、応答性が重要なwebアプリケーションにおいてパフォーマンスを向上させます。
iTextSharp:
リソース管理: iTextSharpを使用した場合、特に大規模なドキュメントや複雑な操作を扱うときにメモリ使用量が増加し、いくつかのケースで性能のボトルネックが発生することがあります。
PDFsharp:
リソース管理: メモリ使用の最適化が不十分で、多数の画像を含む大きなファイルや文書の処理に苦労する可能性があります。
DinkToPdf:
リソース管理: これはしばしば大量のメモリと処理能力を必要とし、非同期操作に対するネイティブサポートが不足しているため、高負荷のシナリオでのパフォーマンスが制限されます。
EvoPDF:
IronPDF:
インストールと統合: NuGetを介して簡単にインストールでき、既存の.NETプロジェクトにスムーズに統合され、最小限の設定で済みます。
iTextSharp:
インストールと統合: NuGetを通じて利用可能ですが、効果的に統合するにはAPIの深い理解が必要です。
PDFsharp:
インストールと統合: NuGetを介して簡単にインストールできますが、HTMLからPDFへの機能は制限されています。
DinkToPdf:
インストールと統合: インストールがより複雑になる可能性があり、wkhtmltopdfのような追加の依存関係を必要とするため、セットアップが複雑になることがあります。
EvoPDF:
IronPDF:
互換性:完全に.NET Core、.NET 5+、および旧.NET Frameworkバージョンと互換性があり、さまざまなプロジェクトタイプにおいて柔軟に対応します。
iTextSharp:
互換性: .NET Framework や .NET Core を含む幅広い環境に適しています。
PDFsharp:
互換性: .NET Framework と .NET Core に対応していますが、高度な機能は制限されています。
DinkToPdf:
互換性: .NET Coreと.NET Frameworkで動作しますが、外部依存関係が必要であり、これが互換性の問題を引き起こす可能性があります。
EvoPDF:
IronPDFは、非同期プログラミングモデルとシームレスに統合し、SemaphoreSlimのような同時実行制御メカニズムを補完します。 これにより、開発者は最小限の労力で、応答性とパフォーマンスに優れたアプリケーションを構築できるようになります。
IronPDFはまた、開発者が効果的なエラーハンドリングを理解し、実践できるよう、広範なドキュメントとサポートリソースを提供します。 この包括的なサポートは、.NETプロジェクトにおけるPDF操作のトラブルシューティングや最適化に役立ちます。
IronPdfは提供します:
PDF API リファレンス: 弊社のツールが提供する機能を最大限に活用できるよう、API リファレンスを提供しています。
詳細については、IronPDFの充実したドキュメントをご覧ください。
.NETアプリケーションの同時実行管理にSemaphoreSlimを使用することは、特にPDF処理のようなリソースを大量に消費するタスクを処理する場合に重要です。 SemaphoreSlimとIronPDFを統合することで、開発者は安全で効率的、かつ信頼性の高い並行性制御を実現し、アプリケーションの応答性とパフォーマンスを維持することができます。
IronPDFがどのようにPDF処理のワークフローを効率化するかをご覧ください。 試してみたい方は、無料トライアルをご利用ください。もしこの強力なツールをプロジェクトで継続して使用したい場合は、ライセンスは$749から始まります。