跳過到頁腳內容
.NET幫助

C# SemaphoreSlim(對開發者如何理解的工作)

並發管理是 C# 中高效能應用程式的重要一環。 它可以確保資源的有效利用,同時避免潛在的衝突或效能瓶頸,因此有一個輕量級的信號控制存取會非常有幫助。 這就是 SemaphoreSlim 發揮作用的地方。 SemaphoreSlim 是一種輕量級同步原語,可控制資源存取,最終防止競賽條件並確保線程安全。

那麼,如果您想要與 PDF 函式庫一起實作,以管理 PDF 的產生流程呢? 您可能正在尋找一個功能強大的 PDF 函式庫,IronPDF 就在此處。 IronPDF 是專為 .NET 開發人員設計的強大 PDF 產生與處理函式庫,在多執行緒環境中使用時,可從並發管理中獲益良多。

如果您想了解SemaphoreSlim和IronPDF的實際應用,請務必繼續閱讀,我們將探討使用SemaphoreSlim的優點,以及如何將其與IronPDF整合,以安全地處理並發操作、提高性能,並確保可靠的PDF處理。

Understanding SemaphoreSlim in C#

什麼是 SemaphoreSlim?

SemaphoreSlim 是 .NET 中的一種同步原語,可限制可同時存取特定資源或資源池的線程數。 它是完整 Semaphore 類別的輕量級版本,設計用來在更簡單、更快速的 Semaphore 已經足夠的情況下更有效率地運作。

使用 SemaphoreSlim 的一些優點是:與 Semaphore 相比,系統開銷有所降低,非常適合管理有限的資源(如資料庫連接或檔案存取),並且支援異步等待方法,非常適合現代的 async/await 程式設計模式。

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
$vbLabelText   $csharpLabel

在程式的運作過程中,當所有可用的許可證都已被線程取走時,semaphore 的計數可以動態地達到零線程。 此狀態表示已達到允許的最大並發存取次數。

如果您願意,您可以設定初始和最大的線程數,從初始的 semaphore 計數為零開始,然後再使用一個獨立的初始化任務,當資源準備就緒時增加 semaphore 計數,允許您選擇的線程數進行。 當 semaphore 計數為零時,線程在嘗試進入 semaphore 時會等待,這稱為"區塊等待"。

您可以追蹤先前的信號量計數,以根據先前的計數調整信號量的行為。 然後可以相應地操作信號量(例如,釋放或等待)。 當執行緒釋放時,semaphore 計數會減少。

控制台輸出

C# Semaphoreslim (How It Works For Developers):圖 1

SemaphoreSlim的常見使用案例

SemaphoreSlim 的一些常見用例如下:

  • 限制對資料庫或檔案系統的存取:它可以防止過多的並發請求壓垮這些資源。
  • 管理線程池:可用於控制執行特定作業的線程數,提高穩定性和效能。

使用 SemaphoreSlim 和 IronPDF 實現安全並發。

在多執行緒環境中設定 IronPDF。

要開始在多執行緒環境中使用 IronPDF,請先安裝 IronPDF NuGet 套件。 您可以導覽至工具 > NuGet Package Manager > NuGet Package Manager for Solution,然後搜尋 IronPDF:

C# Semaphoreslim (How It Works For Developers):圖 2

或在套件管理員控制台執行以下指令:

Install-Package IronPdf

若要開始在程式碼中使用 IronPDF,請確保已將 using IronPdf 語句放在程式碼檔案的頂部。有關在您的環境中設定 IronPDF 的更詳細指南,請查看其入門頁面。

使用 SemaphoreSlim 控制對 PDF 生成的存取

當您使用 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
$vbLabelText   $csharpLabel

在本範例中,我們首先初始化了 SemaphoreSlim,並將 SemaphoreSlim 的初始和最大計數設為 2,將其限制為兩個並發的 PDF 產生作業。 然後,我們建立了一個任務陣列,用來控制程式要執行的任務數量,之後,我們使用 for 迴圈,根據任務陣列內的任務數量動態建立 PDF。

然後使用 WaitAsync() 方法進入信號量,並在 finally 代碼區塊中使用 Release() 來確保即使發生異常,信號量也總是被釋放。 控制台輸出日誌會顯示每項任務開始、完成及釋放信號量的時間,這可讓您追蹤並發行為。

輸出控制台

C# Semaphoreslim (How It Works For Developers):圖 3

輸出 PDF 檔案

C# Semaphoreslim (How It Works For Developers):圖 4

確保 PDF 操作任務中的線程安全

當多個線程與共用資源互動時,線程安全是至關重要的。 在 PDF 操作中,SemaphoreSlim 可確保只有定義數量的線程能同時修改 PDF,防止競賽條件並確保一致性。 在以下程式碼中,我們模擬了一個情境,在多個 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
$vbLabelText   $csharpLabel

透過使用 private static SemaphoreSlim _semaphore = new SemaphoreSlim(1); 將信號量計數設為 1,我們確保一次只能有一個任務操作 PDF。

控制台輸出

C# Semaphoreslim (How It Works For Developers):圖 5

使用 SemaphoreSlim 和 IronPDF 優化性能。

管理資源密集型作業

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
$vbLabelText   $csharpLabel

在處理將大型 HTML 檔案轉換為 PDF 等資源密集型任務時,SemaphoreSlim 可協助平衡負載並優化資源使用。 透過設定 2 個並發作業的限制,我們可以防止系統被資源密集的 PDF 生成任務壓得喘不過氣來。 此方法有助於更平均地分配工作量,提高整體應用程式的效能與穩定性。

輸出影像:使用此方法產生的檔案

C# Semaphoreslim (How It Works For Developers):圖 6

避免並發管理中的死鎖

如果 Semaphores 未正確釋放,可能會發生死鎖。 需要牢記的良好實務是使用 try-finally 區塊,以確保即使發生異常也會釋放 semaphores,防止死鎖並維持應用程式順暢執行。 避免死鎖的一些最佳實踐包括始終在 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
$vbLabelText   $csharpLabel

透過使用 try-catch-finally 塊,我們確保了即使拋出異常,SemaphoreSlim 物件也總是被釋放,從而防止死鎖。 透過記錄錯誤並正確管理信號釋放,我們可以保持程式的穩定,並防止任何意想不到的行為。

從下面的輸出影像中可以看到,我嘗試讓程式載入一個不存在的 HTML 檔案,因此模擬了一個錯誤,但即使有這個錯誤,程式還是列印出錯誤訊息,告訴我出了什麼問題,然後繼續使用 finally 區塊釋放信號量。

C# Semaphoreslim (How It Works For Developers):圖 7

使用 IronPDF 進行 PDF 並發處理的優點

高效可靠的 PDF 處理

IronPDF 旨在高效處理並發的 PDF 處理任務,提供優於許多其他 PDF 函式庫的效能與可靠性。 其強大的架構可隨應用程式的需求而擴充,是高需求環境的理想選擇。 根據效能、易用性和穩健性標準與其他 PDF 函式庫比較,IronPDF 證明是強大的競爭者。 為了展示這一點,我將 IronPDF 與其他幾個流行的 PDF 函式庫進行了比較,例如 iTextSharp、PDFsharp、DinkToPdf 和 EvoPDF:

1.效能

IronPDF:

  • 渲染速度: IronPDF 以其快速高效的渲染能力著稱,尤其是在將 HTML 轉換為 PDF 時。 它使用基於 Chrome 的渲染,可提供高保真的原始 HTML 內容,包括 CSS 和 JavaScript 的執行。
  • 資源管理:與其他函式庫相比,IronPDF 已針對處理大型且複雜的 PDF 進行最佳化,且記憶體使用量較少,因此適用於高容量的應用程式。
  • Asynchronous Operations: 支援異步 PDF 產生,讓反應速度極為重要的 Web 應用程式有更好的效能。

iTextSharp:

  • 渲染速度: iTextSharp 可為文字較多的 PDF 提供良好的效能,但在使用複雜的版面設計或圖片時,速度會顯著變慢。
  • 資源管理:iTextSharp 的記憶體使用量可能較高,尤其是在處理大型文件或複雜的操作時,在某些情況下會導致效能瓶頸。

PDFsharp:

  • 渲染速度:PDFsharp 在處理複雜的版面設計或從 HTML 轉換時,通常會比 IronPDF 慢,因為它缺乏原生的 HTML 渲染引擎。
  • 資源管理:它對記憶體使用的最佳化程度較低,在處理大型檔案或包含大量圖片的文件時可能會很吃力。

DinkToPdf:

  • 渲染速度: DinkToPdf 使用 wkhtmltopdf 引擎,該引擎對於基本的 HTML 至 PDF 轉換很有效,但對於更複雜或動態的內容可能會有困難。
  • 資源管理:它通常需要大量的記憶體和處理能力,而且缺乏對異步作業的原生支援,限制了它在高負載情況下的效能。

EvoPDF:

  • 渲染速度: EvoPDF 同 IronPDF 一樣也提供了基於 Chrome 的渲染,提供了良好的性能,尤其是 HTML 到 PDF 的轉換。
  • 資源管理:它經過了良好的優化,但由於優化不夠積極,在某些情況下可能仍會比 IronPDF 消耗更多的資源。

2.易用性

IronPDF:

  • API 設計: IronPDF 提供現代化、直覺式的 API,讓各種技術層級的開發人員都能輕鬆使用。 該函式庫的設計可與 .NET 應用程式無縫搭配,是 C# 開發人員的最佳選擇。
  • 說明文件與支援:全面的說明文件、大量的程式碼範例以及優異的客戶支援,讓您輕鬆上手並快速解決問題。
  • 安裝與整合:可透過 NuGet 輕鬆安裝,並順利整合至現有的 .NET 專案,只需最少的設定。

iTextSharp:

  • API 設計: iTextSharp 有著陡峭的學習曲線,較為複雜的 API 可能會讓初學者不知所措。 其靈活性是以簡單為代價的。
  • Documentation and Support: 雖然有詳盡的說明文件,但由於配置選項繁多,因此較難找到常見任務的直接範例。
  • 安裝與整合:可透過 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:

  • Feature Set: iTextSharp 非常強大,具有全面的功能集,可支援幾乎所有 PDF 任務,包括複雜的操作和表單處理。
  • 錯誤處理:良好的錯誤處理,但由於函式庫的複雜性,管理起來可能會很複雜。
  • 相容性:非常適合各種環境,包括 .NET Framework 和 .NET Core。

PDFsharp:

  • 功能集:基本的 PDF 創建和處理功能。 缺乏一些進階功能,例如 HTML 到 PDF 的轉換和更複雜的文件編輯。
  • 錯誤處理:基本錯誤處理; 在複雜的情況下,相較於 IronPDF 等更強大的函式庫,IronPDF 的可靠性較低。
  • 相容性:與 .NET Framework 和 .NET Core 相容,但進階功能有限。

DinkToPdf:

  • 功能組合:主要著重於 HTML 至 PDF。 在直接操作 PDF 方面受到限制,並且缺乏註解和表單處理等進階功能。
  • 錯誤處理:基本錯誤處理; 在複雜的 HTML 或大型檔案上容易當機或擱置。
  • 相容性:可與 .NET Core 和 .NET Framework 搭配使用,但需要外部相依性,這可能會引發相容性問題。

EvoPDF:

  • 功能集:提供類似 IronPDF 的強大功能集,包括進階的 HTML 至 PDF 轉換和一些文件處理功能。
  • 錯誤處理:生產環境中強大的錯誤處理和可靠的效能。
  • 相容性:與 .NET Core、.NET Framework 及較新的 .NET 版本完全相容,因此用途廣泛且可靠。

摘要

  • 效能:IronPDF 和 EvoPDF 因其基於 Chrome 的渲染引擎而在效能方面領先,而 iTextSharp 和 PDFsharp 在處理複雜的文件時可能會落後。
  • 易用性: IronPDF 的優勢在於其直觀的 API 和廣泛的說明文件,讓所有層級的開發人員都能使用。 iTextSharp 以簡單為代價提供強大的功能,而 DinkToPdf 和 PDFsharp 則較簡單但功能較少。
  • 穩健性: IronPDF 和 iTextSharp 提供了最穩健的功能集,其中 IronPDF 提供了更簡單的整合和現代化功能(如 async 支援),而 iTextSharp 則涵蓋了更多小眾使用個案,學習曲線較陡。

全面支援異步程式設計

IronPDF 可與 async 程式設計模型無縫整合,與 SemaphoreSlim 等並發控制機制相輔相成。 這樣開發人員就能以最少的工作量建立反應迅速且效能優異的應用程式。

IronPDF 還提供廣泛的文件和支援資源,協助開發人員瞭解並執行有效的錯誤處理作法。 這種全面的支援對於在 .NET 專案中排除故障和優化 PDF 作業非常有價值。

IronPDF 提供:

  • 全面的說明文件: 涵蓋所有功能的廣泛且易於使用的說明文件。
  • 24/5支援:提供積極的工程師支援。
  • 視訊教學:YouTube 上提供了分步視訊指南。
  • 社群論壇:參與社群以獲得更多支援。
  • PDF API 參考:提供 API 參考,讓您可以充分利用我們的工具所提供的功能。

如需更多資訊,請參閱 IronPDF 廣泛的 說明文件

結論

在 .NET 應用程式中使用 SemaphoreSlim 進行並發管理至關重要,尤其是在處理 PDF 等資源密集型任務時。 透過將 SemaphoreSlim 與 IronPDF 整合,開發人員可以實現安全、高效、可靠的並發控制,確保應用程式保持靈敏回應且效能優異。

了解 IronPDF 如何簡化您的 PDF 處理工作流程。 如果您想在專案中繼續使用這款強大的工具,不妨親自體驗一下,它的免費試用版只需 $999。

C# Semaphoreslim (How It Works For Developers):圖 8

常見問題解答

SemaphoreSlim在併發管理中的作用是什麼?

SemaphoreSlim在併發管理中起著至關重要的作用,通過限制同時可以訪問特定資源的線程數來控制併發,這種控制有助於防止競賽條件並確保線程安全,特別是在與IronPDF等庫集成以生成PDF時。

如何將SemaphoreSlim與PDF庫集成以提高性能?

可以將SemaphoreSlim與IronPDF集成以管理並發PDF生成任務的數量。通過這樣做,可以防止性能下降並確保線程同步,從而實現高效的PDF處理。

使用SemaphoreSlim與異步編程的優勢有哪些?

SemaphoreSlim支持異步等待方法,使其非常適合於異步編程模型。該兼容性允許進行響應式應用程序開發,特別是在使用IronPDF生成和操作多線程環境中的PDF時。

SemaphoreSlim如何增強C#應用程序中的PDF生成?

SemaphoreSlim通過確保只有指定數量的線程可以同時訪問PDF生成任務來增強PDF生成。這種受控訪問可防止系統過載並優化IronPDF在C#應用程序中的性能。

多線程PDF生成的一些常見問題是什麼,它們如何可以避免?

常見問題包括競爭條件和死鎖。通過使用SemaphoreSlim與IronPDF,可以限制並發線程數,從而避免競爭條件。此外,確保信號燈適當釋放以防止死鎖。

SemaphoreSlim可以提高並發PDF處理的可靠性嗎?

可以,通過使用SemaphoreSlim與IronPDF,你可以控制同時處理PDF的線程數,從而在多線程環境中增強可靠性和一致性。

與其他庫相比,IronPDF的穩健性來源於什麼?

IronPDF被認為很穩健源於其快速的基於Chrome的渲染引擎、易於使用、豐富的文檔,以及與異步編程模型的無縫集成,使其優於iTextSharp和EvoPDF等庫。

開發者如何學習更多有關SemaphoreSlim和IronPDF的集成?

開發者可以探索IronPDF提供的全麵文檔,其中包括詳細指南、API參考和教程。這些信息結合SemaphoreSlim資源,可以輔助有效地將它們一起實施。

Jacob Mellor, Team Iron 首席技術官
首席技術官

Jacob Mellor是Iron Software的首席技術官,也是開創C# PDF技術的前瞻性工程師。作為Iron Software核心代碼庫的原始開發者,他自公司成立以來就塑造了公司的產品架構,並與CEO Cameron Rimington將公司轉型為服務NASA、Tesla以及全球政府機構的50多人公司。

Jacob擁有曼徹斯特大學土木工程一級榮譽學士學位(1998年–2001年)。他於1999年在倫敦開立首家軟體公司,並於2005年建立了他的第一個.NET組件,專注於解決Microsoft生態系統中的複雜問題。

他的旗艦作品IronPDF和Iron Suite .NET程式庫全球已獲得超過3000萬次NuGet安裝,他的基礎代碼不斷在全球各地驅動開發者工具。擁有25年以上的商業經驗和41年的編碼專業知識,Jacob仍然專注於推動企業級C#、Java和Python PDF技術的創新,同時指導下一代技術領導者。

鋼鐵支援團隊

我們每週 5 天,每天 24 小時在線上。
聊天
電子郵件
打電話給我