.NET 幫助

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

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

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

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

您可以跟踪先前的信号量计数,以根据先前的计数调整信号量的行为,然後相应地操作信号量。(例如,通過釋放或等待). 隨著線程釋放,信號量計數會減少。

控制台輸出

C# SemaphoreSlim(對開發者的運作方式):圖1

SemaphoreSlim 的常見使用情境

SemaphoreSlim 的一些常見用例包括:

  • 限制對資料庫或檔案系統的存取: 這可以防止因併發請求過多而使這些資源不堪重負。
  • 管理線程池: 它可以用來控制執行特定操作的線程數量,從而提高穩定性和效能。

使用 SemaphoreSlim 與 IronPDF 進行安全並發

在多執行緒環境中設置 IronPDF

要在多線程環境中開始使用IronPDF,首先安裝IronPDF NuGet 套件. 您可以藉由導航至工具 > NuGet 套件管理員 > 解決方案的 NuGet 套件管理員,並搜尋 IronPDF 來完成此操作:

C# SemaphoreSlim(對開發人員的工作原理):圖 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 生成。 接著我們創建了一個任務陣列,用來控制程式需要執行的任務數量,之後我們使用一個 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
VB   C#

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

控制台輸出

C# SemaphoreSlim(開發人員如何運作):圖 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# Semaphoreslim(對開發人員的運作方式):圖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# SemaphoreSlim(開發人員如何使用):圖 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,與其他庫相比,使其適合高容量應用程式。
  • 非同步作業: 支援非同步 PDF 生成,在響應性至關重要的網路應用程式中實現更好的效能。

    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可能讓初學者感到不知所措。 它的靈活性是以簡單性為代價的。
  • 文件和支援: 雖然有詳細的文件,但廣泛的配置選項可能使得尋找簡單的常見任務示例變得更加困難。
  • 安裝和整合: 可通過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

< 上一頁
C# Init 關鍵字(開發人員如何使用)
下一個 >
C# try catch finally(開發者如何運作)

準備開始了嗎? 版本: 2024.12 剛剛發布

免費 NuGet 下載 總下載次數: 11,622,374 查看許可證 >