.NET 幫助

C# SemaphoreSlim(開發人員如何使用)

Chipego
奇佩戈·卡林达
2024年10月23日
分享:

介紹

併發管理是 C# 高性能應用程式的一個關鍵方面。 它確保資源得到有效利用,同時避免潛在的衝突或性能瓶頸,因此使用輕量級的信號量來控制訪問可能非常有幫助。 這就是SemaphoreSlim發揮作用的地方。 SemaphoreSlim 是一種輕量級同步基元,可控制資源訪問,最終防止競爭條件並確保執行緒安全。

那麼,如果您想與 PDF 庫一同實施這個以管理 PDF 生成過程,該怎麼辦? 您可能正在尋找一個強大的 PDF 庫,此時 IronPDF 就派上用場了。 IronPDF 是一個強大的 PDF 生成和操作庫,專為 .NET 開發人員設計,在多線程環境使用時可以大大受益於并發管理。

如果您想親眼見證 SemaphoreSlim 和 IronPDF 的運作,請務必繼續閱讀。我們將探討使用 SemaphoreSlim 的好處,以及如何將其與 IronPDF 集成,以安全處理並發操作、提高性能,並確保可靠的 PDF 處理。

理解 C# 中的 SemaphoreSlim

SemaphoreSlim 是什麼?

SemaphoreSlim 是 .NET 中的一種同步原語,用於限制同時訪問特定資源或資源池的線程數量。 它是完整 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

在程式執行過程中,當所有可用的許可證被執行緒獲得時,信號量的計數可以動態地達到零個執行緒。 此狀態表示已達到允許的最大併發訪問數量。

如果您希望,您可以設置初始和最大執行緒數量,將初始信號量計數設為零,然後使用單獨的初始化任務在資源準備就緒時增加信號量計數,允許您選擇的執行緒數量繼續進行。 當信號量計數為零時,線程在嘗試進入信號量時將等待,這稱為「阻塞等待」。

您可以追踪之前的信號量計數,以根據之前的計數調整信號量的行為。 然後,您可以適當地操縱信號量(例如,釋放或等待)。 隨著線程釋放,信號量計數會減少。

控制台輸出

C# Semaphoreslim(如何為開發人員運作):圖 1

SemaphoreSlim 的常見使用情境

SemaphoreSlim 的一些常見用例包括:

  • 限制對資料庫或檔案系統的存取: 它防止這些資源在太多同時請求下被壓垮。
  • 管理線程池:可以用於控制執行特定操作的線程數量,提高穩定性和性能。

使用 SemaphoreSlim 與 IronPDF 進行安全並發

在多執行緒環境中設置 IronPDF

要在多執行緒環境中開始使用IronPDF,首先安裝IronPDF NuGet 套件。 您可以通過導航至 工具 > NuGet 包管理器 > 解決方案的 NuGet 包管理器,然後搜尋 IronPDF 來完成此操作:

C# Semaphoreslim(對開發者的運作方式):圖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() 方法用於進入信號量,而 Release() 在 finally 區塊中使用,以確保即使發生異常,也能始終釋放信號量。 控制台輸出日誌顯示每個任務開始、結束及釋放信號量的時間,這允許您追蹤並發行為。

輸出控制台

C# Semaphoreslim(其如何運作以利開發者):圖3

輸出 PDF 文件

C# Semaphoreslim(對開發人員的運作方式):圖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(對開發者如何運作):圖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(對開發人員的運作原理):圖6

避免死鎖於併發管理

如果信號量未正確釋放,可能會發生死鎖。 要注意的一個好做法是使用 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
$vbLabelText   $csharpLabel

通過使用 try-catch-finally 區塊,我們確保即使拋出異常,SemaphoreSlim 對象也能總是被釋放,從而防止死鎖。 透過記錄錯誤和適當管理信號量釋放,我們可以保持程式穩定並防止任何意外行為。

正如您在下面的輸出圖像中所見,我嘗試讓程序加載不存在的HTML文件以模擬錯誤,但即便出現此錯誤,程序仍然打印錯誤信息告訴我出了什麼問題,然後繼續使用finally區塊釋放信號量。

C# Semaphoreslim(開發者如何使用):圖 7

使用 IronPDF 進行併發 PDF 處理的好處

高效且可靠的 PDF 處理

IronPDF旨在有效地處理並發PDF處理任務,提供優於許多其他PDF庫的性能和可靠性。 其穩健的架構使其能夠隨著應用程式的需求進行擴展,非常適合高需求的環境。 與其他 PDF 函式庫在性能、易用性和穩健性標準上進行比較時,IronPDF 展現了強大的競爭力。 為了展示這一點,我將IronPDF與其他幾個流行的PDF庫進行了比較,如iTextSharp、PDFsharp、DinkToPdf和EvoPDF:

性能

IronPDF:

  • 渲染速度:IronPDF以其快速高效的渲染能力而聞名,尤其是在將HTML轉換為PDF時。 它使用基於 Chrome 的渲染,能高度忠實地再現原始 HTML 內容,包括 CSS 和 JavaScript 的執行。
  • 資源管理:IronPDF 經過優化,能夠以較低的記憶體使用量處理大型和複雜的 PDF 文檔,與其他庫相比更具優勢,這使其適合大流量應用程式。
  • 非同步操作:支援非同步 PDF 生成,允許在回應性至關重要的網路應用程式中具有更好的性能。

    iTextSharp:

  • 渲染速度:iTextSharp 在文本密集型 PDF 中提供良好的性能,但遇到複雜的佈局或圖像時可能會顯著變慢。
  • 資源管理:使用 iTextSharp 時,記憶體使用量可能較高,特別是在處理大型文件或複雜操作時,可能導致某些情況下的效能瓶頸。

    PDFsharp:

  • 呈現速度:與 IronPDF 相比,PDFsharp 在處理複雜佈局或從 HTML 轉換時通常較慢,因為它缺乏原生的 HTML 呈現引擎。
  • 資源管理:它在記憶體使用方面的優化程度較低,可能在處理包含大量圖片的大型檔案或文件時遇到困難。

    DinkToPdf:

  • 渲染速度:DinkToPdf 使用 wkhtmltopdf 引擎,對於基本的 HTML 到 PDF 轉換很有效,但在處理更複雜或動態的內容時可能會遇到困難。
  • 資源管理:這通常需要大量的記憶體和處理能力,並且缺乏對非同步操作的原生支持,限制了其在高負載情境下的性能。

    EvoPDF:

  • 渲染速度:EvoPDF 也提供類似於 IronPDF 的 Chrome-based 渲染,尤其在 HTML 到 PDF 的轉換中,表現良好。
  • 資源管理: 儘管優化良好,但在某些情況下,由於缺乏積極的優化,可能仍會比IronPDF消耗更多資源。

2. 易於使用

IronPDF:

  • API 設計: IronPDF 提供一個現代且直觀的 API,對於各個技能水平的開發人員都非常易於使用。 該函式庫專為與 .NET 應用程式無縫工作而設計,是 C# 開發人員的絕佳選擇。
  • 文件資料和支援:全面的文件資料、大量的代碼範例和出色的客戶支援,讓您可以輕鬆上手並快速解決問題。
  • 安裝和整合:通過 NuGet 簡單安裝,並可順利整合到現有的 .NET 專案中,只需最低限度的配置。

    iTextSharp:

  • API 設計: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:

  • 功能集:提供類似於 IronPDF 的強大功能集,包括先進的 HTML 到 PDF 轉換及一些文件操作功能。
  • 錯誤處理:在生產環境中具有強健的錯誤處理和可靠的性能。
  • 相容性:完全相容於 .NET Core、.NET Framework 以及更新的 .NET 版本,使其既多功能又可靠。

摘要

  • 效能:IronPDF 和 EvoPDF 在效能方面領先,因為它們基於 Chrome 的渲染引擎,而 iTextSharp 和 PDFsharp 在處理複雜文件時可能會落後。
  • 使用方便:IronPDF 憑藉其直觀的 API 和豐富的文件,在所有層次的開發者中都很容易上手。 iTextSharp 以犧牲簡單性為代價提供強大的功能,而 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# Semaphoreslim(開發者如何使用):圖8

Chipego
奇佩戈·卡林达
軟體工程師
Chipego 擁有天生的傾聽技能,這幫助他理解客戶問題,並提供智能解決方案。他在獲得信息技術理學學士學位後,于 2023 年加入 Iron Software 團隊。IronPDF 和 IronOCR 是 Chipego 專注的兩個產品,但隨著他每天找到新的方法來支持客戶,他對所有產品的了解也在不斷增長。他喜歡在 Iron Software 的協作生活,公司內的團隊成員從各自不同的經歷中共同努力,創造出有效的創新解決方案。當 Chipego 離開辦公桌時,他常常享受讀好書或踢足球的樂趣。
< 上一頁
C# Init 關鍵字(開發人員如何使用)
下一個 >
C# try catch finally(開發者如何運作)