.NET ヘルプ

C#セマフォスリム(開発者のための仕組み)

公開済み 2024年10月23日
共有:

イントロダクション

並行性管理は、C#の高性能アプリケーションの重要な側面です。 潜在的な競合やパフォーマンスのボトルネックを回避しながら、リソースを効率的に利用することを保証するため、軽量なセマフォがアクセスを制御することは非常に役立ちます。 ここはセマフォスリム登場します。 SemaphoreSlimは軽量な同期プリミティブで、リソースへのアクセスを制御し、最終的に競合状態を防いでスレッドの安全性を確保します。

では、これをPDF生成プロセスを管理するPDFライブラリと一緒に実装したいとしたらどうでしょう? 以下のような強力なPDFライブラリを探しているかもしれません。IronPDF登場します。 IronPDFは.NET開発者のための堅牢なPDF生成・操作ライブラリで、マルチスレッド環境で使用される場合、並行性管理から大きな恩恵を受けることができます。

SemaphoreSlimとIronPDFが実際に動作しているところをご覧になりたい場合は、SemaphoreSlimを使用する利点と、並行処理を安全に処理し、パフォーマンスを向上させ、信頼できるPDF処理を保証するためにIronPDFと統合する方法を探りますので、ぜひお読みください。

C#のSemaphoreSlimを理解する;

SemaphoreSlimとは?

SemaphoreSlimは、.NETの同期プリミティブで、特定のリソースまたはリソースプールに同時にアクセスできるスレッド数を制限します。 これは完全なSemaphoreクラスの軽量版であり、よりシンプルで高速なセマフォで十分な状況で、より効率的に動作するように設計されています。

SemaphoreSlimを使用する利点は、Semaphoreに比べてシステムのオーバーヘッドが削減され、限られたリソースの管理に最適であることです。(データベース接続やファイルアクセスなど)また、非同期待機メソッドをサポートしているため、最新の非同期/待機プログラミングパターンに適しています。

SemaphoreSlimの基本的な使い方のコード例

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
VB   C#

プログラムの動作中、利用可能なパーミッションがすべてスレッドによって取得されると、セマフォのカウントは動的にゼロスレッドになることがあります。 この状態は、許可された最大同時アクセス数に達したことを示します。

必要であれば、初期スレッド数と最大スレッド数を設定し、初期セマフォ・カウントをゼロで開始し、リソースの準備ができたときにセマフォ・カウントを増加させる別の初期化タスクを使用して、選択したスレッド数で処理を進めることができます。 セマフォのカウントがゼロの場合、スレッドはセマフォに入ろうとすると待機します。

セマフォの動作を調整するために、以前のセマフォのカウントを追跡することができます。(例:リリースまたは待機によって). スレッドが解放されると、セマフォ・カウントが減少します。

コンソール出力

C#セマフォスリム(開発者のための仕組み):図1

SemaphoreSlimの一般的な使用例

SemaphoreSlimの一般的な使用例は以下のとおりです:

  • **データベースやファイルシステムへのアクセスを制限する。
  • スレッドプールの管理: 特定の処理を実行するスレッド数を制御し、安定性とパフォーマンスを向上させるために使用できます。

SemaphoreSlimとIronPDFを使った安全な並行処理

マルチスレッド環境でのIronPDFのセットアップ

マルチスレッド環境でIronPDFを使い始めるには、まずIronPDF NuGetパッケージ. tools > NuGet Package Manager > NuGet Package Manager for Solutionに移動し、IronPDFを検索することで可能です:

C#セマフォスリム(開発者のための仕組み):図2

あるいは、パッケージマネージャーコンソールで次のコマンドを実行してください:

Install-Package IronPdf
Install-Package IronPdf
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'Install-Package IronPdf
VB   C#

あなたのコードでIronPDFを使い始めるには、あなたのコードファイルの先頭に "using IronPdf "ステートメントがあることを確認してください。あなたの環境でIronPDFをセットアップするためのより詳細なガイドについては、そのはじめにページ

SemaphoreSlimでPDF生成へのアクセスを制御する

SemaphoreSlimを使用すると、PDF生成タスクへのアクセスを効果的に制御できます。 これにより、アプリケーションが同時に多くのPDFを生成しようとして、パフォーマンスに影響を与えたり、障害を引き起こしたりしないようにします。

次のコード例は、SemaphoreSlimとIronPDFの基本的な使い方を示しています。

using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
using IronPdf.Exceptions;
using System.Net.Http;
using System.Runtime.CompilerServices;
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;
using IronPdf.Exceptions;
using System.Net.Http;
using System.Runtime.CompilerServices;
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
Imports IronPdf.Exceptions
Imports System.Net.Http
Imports System.Runtime.CompilerServices
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
VB   C#

この例では、まずSemaphoreSlimを初期化し、SemaphoreSlimの初期カウントと最大カウントを'2'に設定し、同時PDF生成を2回に制限しています。 次に、プログラムが行うべきタスクの数を制御するために使用されるタスク配列を作成し、その後、タスク配列内のタスクの数に基づいて動的にPDFを作成するためにforループを使用します。

The `WaitAsync()\次に、セマフォを入力するために`メソッドが使用され、Release()\例外が発生した場合でも、セマフォが常に解放されるようにするために、finally ブロックで ``*** が使用されています。 コンソール出力ログは、各タスクがいつ開始し、いつ終了し、セマフォを解放したかを示し、これにより並行動作の追跡が可能になります。

出力コンソール

C#セマフォスリム(開発者のための仕組み):図3

出力PDFファイル

C#セマフォスリム(開発者のための仕組み):図4

PDF操作タスクにおけるスレッドの安全性の確保

スレッドセーフは、複数のスレッドが共有リソースとやり取りする際に非常に重要です。 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
VB   C#

を使用してセマフォカウントを1に設定します。(1)\また、一度に1つのタスクだけがPDFを操作できるようにします。

コンソール出力

C#セマフォスリム(開発者のための仕組み):図5

SemaphoreSlimとIronPDFによるパフォーマンスの最適化

リソース集約型オペレーションの管理

IronPDFは大きなHTMLファイルをPDFに変換するようなリソース集約的なタスクを処理し、非同期環境でこれらのタスクを実行することに優れています。 SemaphoreSlimを使用してこれらの操作を管理することで、高負荷時でもパフォーマンスを低下させることなくアプリケーションの応答性を維持することができます。

次のコード例は、システムリソースに過負荷をかけないように、同時に行われる大きなHTMLからPDFへの変換の数を制限する必要があるシナリオを示しています。

using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
using IronPdf.Exceptions;
using System.Net.Http;
using System.Runtime.CompilerServices;
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;
using IronPdf.Exceptions;
using System.Net.Http;
using System.Runtime.CompilerServices;
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
Imports IronPdf.Exceptions
Imports System.Net.Http
Imports System.Runtime.CompilerServices
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
VB   C#

大きなHTMLファイルをPDFに変換するようなリソースを大量に必要とするタスクでは、SemaphoreSlimが負荷のバランスをとり、リソースの使用を最適化します。 同時処理の上限を2つに設定することで、リソース集約的なPDF生成タスクによってシステムが圧倒されるのを防ぎます。 このアプローチにより、作業負荷が均等に分散され、アプリケーション全体のパフォーマンスと安定性が向上します。

出力イメージ:このメソッドで生成されたファイル

C#セマフォスリム(開発者のための仕組み):図6

同時実行管理におけるデッドロックの回避

セマフォが正しく解放されないと、デッドロックが発生する可能性があります。 留意すべき良い習慣は、例外が発生してもセマフォが解放されるようにtry-finallyブロックを使用することです。 デッドロックを回避するために覚えておくべきベストプラクティスには、必ずfinallyブロックの中でセマフォを解放すること、 `.wait のようなブロッキングコールを使用しないことなどがあります。()\非同期コードの中に.Result`を記述してください。

using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
using IronPdf.Exceptions;
using System.Net.Http;
using System.Runtime.CompilerServices;
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;
using IronPdf.Exceptions;
using System.Net.Http;
using System.Runtime.CompilerServices;
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
Imports IronPdf.Exceptions
Imports System.Net.Http
Imports System.Runtime.CompilerServices
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
VB   C#

Try-catch-finally-***ブロックを使用することで、例外がスローされてもSemaphoreSlimオブジェクトが常に解放されるようにし、デッドロックを防止しています。 エラーをログに記録し、セマフォの解放を適切に管理することで、プログラムを安定させ、予期せぬ動作を防ぐことができます。

下の出力画像でわかるように、存在しないHTMLファイルをプログラムに読み込ませようとしてエラーをシミュレートしましたが、このエラーでも、プログラムは何が間違っていたかを教えてくれるエラーメッセージを表示し、finallyブロックを使ってセマフォの解放に進みます。

C#セマフォスリム(開発者のための仕組み):図7

並行PDF処理にIronPDFを使うメリット

効率的で信頼性の高いPDF処理

IronPDFは同時PDF処理タスクを効率的に処理するように設計されており、他の多くのPDFライブラリよりも優れたパフォーマンスと信頼性を提供します。 堅牢なアーキテクチャにより、アプリケーションのニーズに合わせて拡張できるため、需要の高い環境に最適です。 パフォーマンス、使いやすさ、堅牢性を基準に他のPDFライブラリと比較すると、IronPDFは強力な競争相手であることがわかります。 これを紹介するために、私はIronPDFをiTextSharp, PDFsharp, DinkToPdf, EvoPDFのような他の人気のあるPDFライブラリと比較しました:

1. **パフォーマンス

IronPDF:

  • レンダリング速度: IronPDFは特にHTMLをPDFに変換する際に、その高速で効率的なレンダリング機能で知られています。 Chromeベースのレンダリングを使用しているため、CSSやJavaScriptの実行を含め、元のHTMLコンテンツに忠実です。
  • リソース管理: IronPDFは大きく複雑なPDFを処理するために最適化されており、他のライブラリと比較してメモリ使用量が少なく、大量のアプリケーションに適しています。
  • 非同期操作: 非同期 PDF 生成をサポートし、応答性が重要な Web アプリケーションでより良いパフォーマンスを可能にします。

    iTextSharp:

  • レンダリング速度: iTextSharpは、テキストが多いPDFには良いパフォーマンスを提供しますが、複雑なレイアウトや画像を使用すると大幅に遅くなる可能性があります。
  • リソース管理: iTextSharpでは、特に大きな文書や複雑な操作を行う場合にメモリ使用量が多くなり、パフォーマンスのボトルネックになる場合があります。

    PDFsharp:

  • レンダリング速度: PDFsharpはネイティブのHTMLレンダリングエンジンを持たないため、複雑なレイアウトやHTMLからの変換を行う場合、IronPDFに比べて一般的に遅くなります。
  • *リソース管理:*** メモリ使用量があまり最適化されていないため、大きなファイルや多数の画像を含む文書で苦労することがあります。

    DinkToPdf:

  • **DinkToPdf はwkhtmltopdfエンジンを使用しており、基本的な HTML から PDF への変換には効果的ですが、複雑なコンテンツや動的なコンテンツでは苦戦する可能性があります。
  • リソース管理: 多くの場合、多大なメモリと処理能力を必要とし、非同期操作のネイティブサポートがないため、高負荷シナリオでのパフォーマンスが制限されます。

    EvoPDF:

  • レンダリング速度: EvoPDFもIronPDFのようにIronPDFベースのレンダリングを提供し、特にHTMLからPDFへの変換に優れたパフォーマンスを提供します。
  • リソース管理: よく最適化されていますが、あまり積極的に最適化されていないため、シナリオによってはIronPDFと比較してより多くのリソースを消費する可能性があります。

2. **使いやすさ

IronPDF:

  • APIデザイン: IronPDFはあらゆるレベルの開発者が使いやすい、モダンで直感的なAPIを提供します。 このライブラリは、.NETアプリケーションとシームレスに動作するように設計されているため、C#開発者に最適です。
  • ドキュメントとサポート: 包括的なドキュメント、多数のコード例、および優れた顧客サポートにより、簡単に開始し、問題を迅速に解決することができます。
  • インストールと統合: NuGet経由で簡単にインストールでき、既存の.NETプロジェクトにスムーズに統合できるため、最小限の設定しか必要としません。

    iTextSharp:

  • **iTextSharpは学習曲線が急で、初心者には圧倒されるような複雑なAPIを持っています。 その柔軟性は、シンプルさを犠牲にしています。
  • ドキュメントとサポート: よくドキュメント化されていますが、広範な設定オプションがあるため、一般的なタスクのわかりやすい例を見つけるのが難しくなります。
  • インストールと統合: NuGetを通じて利用可能ですが、効果的に統合するにはAPIをより深く理解する必要があります。

    PDFsharp:

  • APIデザイン: PDFsharpは、基本的なPDFタスクのためにシンプルに設計されていますが、すぐに使える高度な機能がないため、より複雑なシナリオでの使用が制限される可能性があります。
  • ドキュメンテーションとサポート: 基本的なドキュメンテーションはありますが、IronPDFと比べるとあまり充実しておらず、高度な使い方のための詳細な例がありません。
  • インストールと統合: NuGet経由で簡単にインストールできますが、HTMLからPDFへの機能は限られています。

    DinkToPdf:

  • APIデザイン: DinkToPdfのAPIは比較的シンプルですが、IronPdfに比べると洗練されていません。 主にHTMLからPDFへの変換を対象としており、PDFを直接操作するための機能はあまり提供していません。
  • ドキュメントとサポート: ドキュメントは限られており、コミュニティサポートは他のライブラリほど強固ではないため、トラブルシューティングがより困難になります。
  • インストールと統合: wkhtmltopdf のような追加の依存関係を必要とするため、インストールが複雑になることがあります。

    EvoPDF:

  • APIデザイン: EvoPDFはIronPDFに似たわかりやすいAPIを提供し、使いやすさを念頭に置いたHTMLからPDFへの変換に重点を置いています。
  • ドキュメンテーションとサポート: ドキュメンテーションは充実しており、サポートオプションも充実していますが、コミュニティ主導の例ではIronPDFほど充実していません。
  • インストールと統合: NuGetパッケージが利用可能で、.NETプロジェクトに簡単に統合できます。

3. **堅牢性

IronPDF:

  • **IronPDFは非常に堅牢で、HTMLからPDFへの変換、PDF編集、テキスト抽出、暗号化、注釈、電子署名を含む幅広い機能をサポートしています。
  • エラー処理: 堅牢なエラー処理と例外管理を提供し、本番環境での信頼性を高めます。
  • 互換性: .NET Core、.NET 5+、およびレガシーの.NET Frameworkバージョンと完全な互換性があり、さまざまなプロジェクトタイプで汎用性があります。

    iTextSharp:

  • **iTextSharp は、複雑な操作やフォーム処理など、ほとんどすべての PDF タスクをサポートする包括的な機能セットで非常に堅牢です。
  • エラー処理: 優れたエラー処理ですが、ライブラリが複雑なため、管理が複雑になる可能性があります。
  • **.NET Frameworkや.NET Coreを含む幅広い環境に適しています。

    PDFsharp:

  • **基本的なPDFの作成と操作機能。 HTMLからPDFへの変換や、より洗練されたドキュメント編集など、高度な機能が欠けています。
  • エラー処理: 基本的なエラー処理; は、IronPDFのようなより堅牢なライブラリと比較して、複雑なシナリオでは信頼性が低いです。
  • **.NET Frameworkおよび.NET Coreと互換性がありますが、高度な機能には制限があります。

    DinkToPdf:

  • 機能セット: 主にHTMLからPDFへの翻訳に重点を置いています。 PDFの直接操作には制限があり、注釈やフォーム処理などの高度な機能はありません。
  • エラー処理: 基本的なエラー処理; 複雑なHTMLや大きなファイルでクラッシュやハングアップしやすい。
  • 互換性: .NET Coreと.NET Frameworkで動作しますが、外部依存関係が必要なため、互換性の問題が発生する可能性があります。

    EvoPDF:

  • 機能セット: 高度なHTMLからPDFへの変換といくつかの文書操作機能を含む、IronPDFに似た強力な機能セットを提供します。
  • エラー処理: 堅牢なエラー処理と本番環境での信頼できるパフォーマンス。
  • 互換性: .NET Core、.NET Framework、および新しい.NETバージョンと完全に互換性があり、汎用性と信頼性があります。

サマリー

  • パフォーマンス: IronPDFとEvoPDFはChromeベースのレンダリングエンジンによりパフォーマンスをリードしていますが、iTextSharpとPDFsharpは複雑なドキュメントの処理で遅れをとる可能性があります。
  • 使いやすさ: IronPDFは直感的なAPIと広範なドキュメントで優れており、すべてのレベルの開発者がアクセスできます。 DinkToPdfとPDFsharpは簡単ですが、機能はそれほど多くありません。
  • 堅牢性: IronPDFとiTextSharpは最も堅牢な機能セットを提供し、IronPDFはよりシンプルな統合と非同期サポートのような最新機能を提供し、iTextSharpはよりニッチなユースケースをカバーし、学習曲線はより急です。

非同期プログラミングの包括的サポート

IronPdfは以下とシームレスに統合します。非同期SemaphoreSlimのような同時実行制御メカニズムを補完するプログラミングモデル。 これにより、開発者は最小限の労力で、応答性とパフォーマンスに優れたアプリケーションを構築できるようになります。

IronPDFはまた、開発者が効果的なエラーハンドリングを理解し、実践できるよう、広範なドキュメントとサポートリソースを提供します。 この包括的なサポートは、.NETプロジェクトにおけるPDF操作のトラブルシューティングや最適化に役立ちます。

IronPdfは提供します:

  • 包括的なドキュメント:すべての機能を網羅した分かりやすいドキュメント。
  • 24/5 サポート: エンジニアによるサポートが利用可能です。
  • ビデオチュートリアル:ステップバイステップのビデオガイドがYouTubeで利用できます。
  • コミュニティフォーラム: 追加サポートのための積極的なコミュニティ。
  • PDF APIリファレンス: 弊社のツールの提供する機能を最大限に活用できるように、APIリファレンスを提供します。

    詳しい情報は、IronPDFの詳細をご覧ください。ドキュメント.

結論

.NETアプリケーションの同時実行管理にSemaphoreSlimを使用することは、特にPDF処理のようなリソースを大量に消費するタスクを処理する場合に重要です。 SemaphoreSlimとIronPDFを統合することで、開発者は安全で効率的、かつ信頼性の高い並行性制御を実現し、アプリケーションの応答性とパフォーマンスを維持することができます。

IronPDFがどのようにPDF処理のワークフローを効率化するかをご覧ください。 この翻訳を無料試用あなたのプロジェクトでこの強力なツールを使い続けたい場合は、わずか749ドルから始めることができます。

C#セマフォスリム(開発者のための仕組み):図8

< 以前
C# Init キーワード(開発者のための仕組み)
次へ >
C# try catch finally (開発者のための仕組み)