在生產環境中測試,無水印。
在任何需要的地方都能運行。
獲得 30 天的全功能產品。
在幾分鐘內上手運行。
試用產品期間完全訪問我們的支援工程團隊
併發管理是 C# 高性能應用程式的一個關鍵方面。 它確保資源得到有效利用,同時避免潛在的衝突或性能瓶頸,因此使用輕量級的信號量來控制訪問可能非常有幫助。 這就是SemaphoreSlim發揮作用的地方。 SemaphoreSlim 是一種輕量級同步基元,可控制資源訪問,最終防止競爭條件並確保執行緒安全。
那麼,如果您想與 PDF 庫一同實施這個以管理 PDF 生成過程,該怎麼辦? 您可能正在尋找一個強大的 PDF 庫,此時 IronPDF 就派上用場了。 IronPDF 是一個強大的 PDF 生成和操作庫,專為 .NET 開發人員設計,在多線程環境使用時可以大大受益於并發管理。
如果您想親眼見證 SemaphoreSlim 和 IronPDF 的運作,請務必繼續閱讀。我們將探討使用 SemaphoreSlim 的好處,以及如何將其與 IronPDF 集成,以安全處理並發操作、提高性能,並確保可靠的 PDF 處理。
SemaphoreSlim 是 .NET 中的一種同步原語,用於限制同時訪問特定資源或資源池的線程數量。 它是完整 Semaphore 類別的輕量化版本,專為在需要簡單、更快速信號量的情況下更加高效地運行而設計。
使用 SemaphoreSlim 的一些好處是系統開銷比 Semaphore 減少,更適合管理有限資源(如資料庫連接或文件訪問),並且支持非同步等待方法,非常適合現代 async/await 編程模式。
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
// Semaphore count
private static SemaphoreSlim _semaphore = new SemaphoreSlim(3); // Limit to 3 concurrent threads.
static async Task Main(string[] args)
{
// Start tasks that will wait on the semaphore.
var tasks = new Task[5];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = Task.Run(() => AccessResource(i));
}
// Simulate some work in the main thread (e.g., initialization).
Console.WriteLine("Main thread is preparing resources...");
await Task.Delay(2000); // Simulate initialization delay.
// Main thread calls release, releases semaphore permits to allow waiting tasks to proceed.
Console.WriteLine("Main thread releasing semaphore permits...");
_semaphore.Release(2); // Releases 2 permits, allowing up to 2 tasks to proceed.
// Wait for all tasks to complete.
await Task.WhenAll(tasks);
Console.WriteLine("All tasks completed.");
}
static async Task AccessResource(int id)
{
Console.WriteLine($"Task {id} waiting to enter...");
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"Current thread successfully entered by Task {id}.");
await Task.Delay(1000); // Simulate work.
}
finally
{
Console.WriteLine($"Task {id} releasing.");
_semaphore.Release();
}
}
}
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
// Semaphore count
private static SemaphoreSlim _semaphore = new SemaphoreSlim(3); // Limit to 3 concurrent threads.
static async Task Main(string[] args)
{
// Start tasks that will wait on the semaphore.
var tasks = new Task[5];
for (int i = 0; i < tasks.Length; i++)
{
tasks[i] = Task.Run(() => AccessResource(i));
}
// Simulate some work in the main thread (e.g., initialization).
Console.WriteLine("Main thread is preparing resources...");
await Task.Delay(2000); // Simulate initialization delay.
// Main thread calls release, releases semaphore permits to allow waiting tasks to proceed.
Console.WriteLine("Main thread releasing semaphore permits...");
_semaphore.Release(2); // Releases 2 permits, allowing up to 2 tasks to proceed.
// Wait for all tasks to complete.
await Task.WhenAll(tasks);
Console.WriteLine("All tasks completed.");
}
static async Task AccessResource(int id)
{
Console.WriteLine($"Task {id} waiting to enter...");
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"Current thread successfully entered by Task {id}.");
await Task.Delay(1000); // Simulate work.
}
finally
{
Console.WriteLine($"Task {id} releasing.");
_semaphore.Release();
}
}
}
Imports System
Imports System.Threading
Imports System.Threading.Tasks
Friend Class Program
' Semaphore count
Private Shared _semaphore As New SemaphoreSlim(3) ' Limit to 3 concurrent threads.
Shared Async Function Main(ByVal args() As String) As Task
' Start tasks that will wait on the semaphore.
Dim tasks = New Task(4){}
For i As Integer = 0 To tasks.Length - 1
tasks(i) = Task.Run(Function() AccessResource(i))
Next i
' Simulate some work in the main thread (e.g., initialization).
Console.WriteLine("Main thread is preparing resources...")
Await Task.Delay(2000) ' Simulate initialization delay.
' Main thread calls release, releases semaphore permits to allow waiting tasks to proceed.
Console.WriteLine("Main thread releasing semaphore permits...")
_semaphore.Release(2) ' Releases 2 permits, allowing up to 2 tasks to proceed.
' Wait for all tasks to complete.
Await Task.WhenAll(tasks)
Console.WriteLine("All tasks completed.")
End Function
Private Shared Async Function AccessResource(ByVal id As Integer) As Task
Console.WriteLine($"Task {id} waiting to enter...")
Await _semaphore.WaitAsync()
Try
Console.WriteLine($"Current thread successfully entered by Task {id}.")
Await Task.Delay(1000) ' Simulate work.
Finally
Console.WriteLine($"Task {id} releasing.")
_semaphore.Release()
End Try
End Function
End Class
在程式執行過程中,當所有可用的許可證被執行緒獲得時,信號量的計數可以動態地達到零個執行緒。 此狀態表示已達到允許的最大併發訪問數量。
如果您希望,您可以設置初始和最大執行緒數量,將初始信號量計數設為零,然後使用單獨的初始化任務在資源準備就緒時增加信號量計數,允許您選擇的執行緒數量繼續進行。 當信號量計數為零時,線程在嘗試進入信號量時將等待,這稱為「阻塞等待」。
您可以追踪之前的信號量計數,以根據之前的計數調整信號量的行為。 然後,您可以適當地操縱信號量(例如,釋放或等待)。 隨著線程釋放,信號量計數會減少。
C# Semaphoreslim(如何為開發人員運作):圖 1
SemaphoreSlim 的一些常見用例包括:
要在多執行緒環境中開始使用IronPDF,首先安裝IronPDF NuGet 套件。 您可以通過導航至 工具 > NuGet 包管理器 > 解決方案的 NuGet 包管理器,然後搜尋 IronPDF 來完成此操作:
或者,您也可以在套件管理器主控台中執行以下命令:
Install-Package IronPdf
要在代碼中開始使用IronPDF,請確保在代碼文件的頂部放置using IronPdf
語句。如需更深入的IronPDF設置指南,請查看其入門頁面。
當使用 SemaphoreSlim 時,您可以有效地控制對 PDF 生成任務的訪問。 這可確保您的應用程式不會嘗試同時生成過多的PDF,這可能會影響性能或導致故障。
以下範例代碼展示了 SemaphoreSlim 與 IronPDF 的基本用法。
using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
private static SemaphoreSlim _semaphore = new SemaphoreSlim(2); // Limit to 2 concurrent threads.
static async Task Main(string[] args)
{
var tasks = new Task[5];
for (int i = 0; i < tasks.Length; i++)
{
string htmlContent = $"<h1>PDF Document {i}</h1><p>This is a sample PDF content for task {i}.</p>";
string outputPath = $"output_{i}.pdf";
// Start multiple tasks to demonstrate controlled concurrency.
tasks[i] = GeneratePdfAsync(htmlContent, outputPath, i);
}
await Task.WhenAll(tasks);
}
static async Task GeneratePdfAsync(string htmlContent, string outputPath, int taskId)
{
Console.WriteLine($"Task {taskId} is waiting for access...");
// Wait to enter the semaphore.
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"Task {taskId} has started PDF generation.");
ChromePdfRenderer renderer = new ChromePdfRenderer();
PdfDocument pdf = await renderer.RenderHtmlAsPdfAsync(htmlContent);
pdf.SaveAs(outputPath);
Console.WriteLine($"Task {taskId} has completed PDF generation.");
}
finally
{
// Ensure semaphore is released to allow other tasks to proceed.
_semaphore.Release();
Console.WriteLine($"Task {taskId} has released semaphore.");
}
}
}
using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
private static SemaphoreSlim _semaphore = new SemaphoreSlim(2); // Limit to 2 concurrent threads.
static async Task Main(string[] args)
{
var tasks = new Task[5];
for (int i = 0; i < tasks.Length; i++)
{
string htmlContent = $"<h1>PDF Document {i}</h1><p>This is a sample PDF content for task {i}.</p>";
string outputPath = $"output_{i}.pdf";
// Start multiple tasks to demonstrate controlled concurrency.
tasks[i] = GeneratePdfAsync(htmlContent, outputPath, i);
}
await Task.WhenAll(tasks);
}
static async Task GeneratePdfAsync(string htmlContent, string outputPath, int taskId)
{
Console.WriteLine($"Task {taskId} is waiting for access...");
// Wait to enter the semaphore.
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"Task {taskId} has started PDF generation.");
ChromePdfRenderer renderer = new ChromePdfRenderer();
PdfDocument pdf = await renderer.RenderHtmlAsPdfAsync(htmlContent);
pdf.SaveAs(outputPath);
Console.WriteLine($"Task {taskId} has completed PDF generation.");
}
finally
{
// Ensure semaphore is released to allow other tasks to proceed.
_semaphore.Release();
Console.WriteLine($"Task {taskId} has released semaphore.");
}
}
}
Imports IronPdf
Imports System
Imports System.Threading
Imports System.Threading.Tasks
Friend Class Program
Private Shared _semaphore As New SemaphoreSlim(2) ' Limit to 2 concurrent threads.
Shared Async Function Main(ByVal args() As String) As Task
Dim tasks = New Task(4){}
For i As Integer = 0 To tasks.Length - 1
Dim htmlContent As String = $"<h1>PDF Document {i}</h1><p>This is a sample PDF content for task {i}.</p>"
Dim outputPath As String = $"output_{i}.pdf"
' Start multiple tasks to demonstrate controlled concurrency.
tasks(i) = GeneratePdfAsync(htmlContent, outputPath, i)
Next i
Await Task.WhenAll(tasks)
End Function
Private Shared Async Function GeneratePdfAsync(ByVal htmlContent As String, ByVal outputPath As String, ByVal taskId As Integer) As Task
Console.WriteLine($"Task {taskId} is waiting for access...")
' Wait to enter the semaphore.
Await _semaphore.WaitAsync()
Try
Console.WriteLine($"Task {taskId} has started PDF generation.")
Dim renderer As New ChromePdfRenderer()
Dim pdf As PdfDocument = Await renderer.RenderHtmlAsPdfAsync(htmlContent)
pdf.SaveAs(outputPath)
Console.WriteLine($"Task {taskId} has completed PDF generation.")
Finally
' Ensure semaphore is released to allow other tasks to proceed.
_semaphore.Release()
Console.WriteLine($"Task {taskId} has released semaphore.")
End Try
End Function
End Class
在此範例中,我們首先初始化了 SemaphoreSlim,並將 SemaphoreSlim 的初始和最大計數設置為「2」,限制其進行兩個同時的 PDF 生成。 接著我們創建了一個任務陣列,用來控制程式需要執行的任務數量,之後我們使用一個 for 迴圈根據任務陣列中的任務數量動態創建 PDF。
WaitAsync()
方法用於進入信號量,而 Release()
在 finally 區塊中使用,以確保即使發生異常,也能始終釋放信號量。 控制台輸出日誌顯示每個任務開始、結束及釋放信號量的時間,這允許您追蹤並發行為。
當多個執行緒與共享資源交互時,執行緒安全性至關重要。 在 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
通過使用private static SemaphoreSlim _semaphore = new SemaphoreSlim(1);
將信號量計數設定為1,我們確保一次只有一個任務可以操控PDF。
IronPDF 擅長處理資源密集型任務,例如將大型 HTML 文件轉換為 PDF,並在異步環境中出色地完成這些任務。 使用 SemaphoreSlim 管理這些操作可確保您的應用程式即使在重負載下也能保持響應性而不會失去性能。
以下範例代碼展示了一種情境,我們需要限制 HTML 轉 PDF 的同時進行次數,以避免系統資源過載。
using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
// Limit concurrent large PDF conversions to 2.
private static SemaphoreSlim _semaphore = new SemaphoreSlim(2);
static async Task Main(string[] args)
{
var tasks = new Task[4];
for (int i = 0; i < tasks.Length; i++)
{
string htmlContent = $"<h1>Large Document {i}</h1><p>Content for a large HTML file {i}.</p>";
string outputPath = $"large_output_{i}.pdf";
// Start multiple tasks to convert large HTML files to PDFs.
tasks[i] = ConvertLargeHtmlAsync(htmlContent, outputPath, i);
}
await Task.WhenAll(tasks); // Wait for all tasks to finish.
}
// Method to convert large HTML to PDF using SemaphoreSlim to control resource usage.
public static async Task ConvertLargeHtmlAsync(string htmlContent, string outputPath, int taskId)
{
Console.WriteLine($"Task {taskId} is waiting to start conversion...");
// Wait to enter the semaphore.
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"Task {taskId} is converting large HTML to PDF.");
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(htmlContent); // Convert large HTML to PDF
pdf.SaveAs(outputPath); // Save the PDF file
Console.WriteLine($"Task {taskId} has completed conversion.");
}
finally
{
// Ensure the semaphore is released to allow other tasks to proceed.
_semaphore.Release();
Console.WriteLine($"Task {taskId} has released semaphore.");
}
}
}
using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
// Limit concurrent large PDF conversions to 2.
private static SemaphoreSlim _semaphore = new SemaphoreSlim(2);
static async Task Main(string[] args)
{
var tasks = new Task[4];
for (int i = 0; i < tasks.Length; i++)
{
string htmlContent = $"<h1>Large Document {i}</h1><p>Content for a large HTML file {i}.</p>";
string outputPath = $"large_output_{i}.pdf";
// Start multiple tasks to convert large HTML files to PDFs.
tasks[i] = ConvertLargeHtmlAsync(htmlContent, outputPath, i);
}
await Task.WhenAll(tasks); // Wait for all tasks to finish.
}
// Method to convert large HTML to PDF using SemaphoreSlim to control resource usage.
public static async Task ConvertLargeHtmlAsync(string htmlContent, string outputPath, int taskId)
{
Console.WriteLine($"Task {taskId} is waiting to start conversion...");
// Wait to enter the semaphore.
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"Task {taskId} is converting large HTML to PDF.");
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(htmlContent); // Convert large HTML to PDF
pdf.SaveAs(outputPath); // Save the PDF file
Console.WriteLine($"Task {taskId} has completed conversion.");
}
finally
{
// Ensure the semaphore is released to allow other tasks to proceed.
_semaphore.Release();
Console.WriteLine($"Task {taskId} has released semaphore.");
}
}
}
Imports IronPdf
Imports System
Imports System.Threading
Imports System.Threading.Tasks
Friend Class Program
' Limit concurrent large PDF conversions to 2.
Private Shared _semaphore As New SemaphoreSlim(2)
Shared Async Function Main(ByVal args() As String) As Task
Dim tasks = New Task(3){}
For i As Integer = 0 To tasks.Length - 1
Dim htmlContent As String = $"<h1>Large Document {i}</h1><p>Content for a large HTML file {i}.</p>"
Dim outputPath As String = $"large_output_{i}.pdf"
' Start multiple tasks to convert large HTML files to PDFs.
tasks(i) = ConvertLargeHtmlAsync(htmlContent, outputPath, i)
Next i
Await Task.WhenAll(tasks) ' Wait for all tasks to finish.
End Function
' Method to convert large HTML to PDF using SemaphoreSlim to control resource usage.
Public Shared Async Function ConvertLargeHtmlAsync(ByVal htmlContent As String, ByVal outputPath As String, ByVal taskId As Integer) As Task
Console.WriteLine($"Task {taskId} is waiting to start conversion...")
' Wait to enter the semaphore.
Await _semaphore.WaitAsync()
Try
Console.WriteLine($"Task {taskId} is converting large HTML to PDF.")
Dim renderer = New ChromePdfRenderer()
Dim pdf = Await renderer.RenderHtmlAsPdfAsync(htmlContent) ' Convert large HTML to PDF
pdf.SaveAs(outputPath) ' Save the PDF file
Console.WriteLine($"Task {taskId} has completed conversion.")
Finally
' Ensure the semaphore is released to allow other tasks to proceed.
_semaphore.Release()
Console.WriteLine($"Task {taskId} has released semaphore.")
End Try
End Function
End Class
在處理資源密集型任務(如將大型 HTML 文件轉換為 PDF)時,SemaphoreSlim 可以有助於平衡負載並優化資源使用。 通過設定 2 個同時操作的限制,我們防止系統因資源密集型的 PDF 生成任務而不堪重負。 這種方法有助於更均勻地分配工作負荷,從而提高整體應用程式的性能和穩定性。
如果信號量未正確釋放,可能會發生死鎖。 要注意的一個好做法是使用 try-finally 區塊,以確保在發生異常時仍能釋放信號量,防止死鎖並保持應用程式順暢運行。 避免死鎖的一些最佳實踐包括總是在 finally
區塊中釋放信號量,並避免在非同步代碼中使用像 Wait()
和 Result
這樣的阻塞調用。
using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
private static SemaphoreSlim _semaphore = new SemaphoreSlim(3);
static async Task Main(string[] args)
{
var tasks = new Task[3];
for (int i = 0; i < tasks.Length; i++)
{
string content = $"<h1>Document {i}</h1><p>Content for PDF {i}.</p>";
string path = $"safe_output_{i}.pdf";
// Start multiple tasks to demonstrate deadlock-free semaphore usage.
tasks[i] = SafePdfTaskAsync(content, path, i);
}
await Task.WhenAll(tasks); // Wait for all tasks to finish.
}
// Method demonstrating best practices for using SemaphoreSlim to avoid deadlocks.
public static async Task SafePdfTaskAsync(string content, string path, int taskId)
{
Console.WriteLine($"Task {taskId} is waiting to generate PDF...");
// Wait to enter the semaphore.
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"Task {taskId} is generating PDF.");
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(content); // Render HTML to PDF
pdf.SaveAs(path); // Save the PDF
Console.WriteLine($"Task {taskId} has completed PDF generation.");
}
catch (Exception ex)
{
Console.WriteLine($"Task {taskId} encountered an error: {ex.Message}");
}
finally
{
// Always release the semaphore, even if an error occurs.
_semaphore.Release();
Console.WriteLine($"Task {taskId} has released semaphore.");
}
}
}
using IronPdf;
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
private static SemaphoreSlim _semaphore = new SemaphoreSlim(3);
static async Task Main(string[] args)
{
var tasks = new Task[3];
for (int i = 0; i < tasks.Length; i++)
{
string content = $"<h1>Document {i}</h1><p>Content for PDF {i}.</p>";
string path = $"safe_output_{i}.pdf";
// Start multiple tasks to demonstrate deadlock-free semaphore usage.
tasks[i] = SafePdfTaskAsync(content, path, i);
}
await Task.WhenAll(tasks); // Wait for all tasks to finish.
}
// Method demonstrating best practices for using SemaphoreSlim to avoid deadlocks.
public static async Task SafePdfTaskAsync(string content, string path, int taskId)
{
Console.WriteLine($"Task {taskId} is waiting to generate PDF...");
// Wait to enter the semaphore.
await _semaphore.WaitAsync();
try
{
Console.WriteLine($"Task {taskId} is generating PDF.");
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(content); // Render HTML to PDF
pdf.SaveAs(path); // Save the PDF
Console.WriteLine($"Task {taskId} has completed PDF generation.");
}
catch (Exception ex)
{
Console.WriteLine($"Task {taskId} encountered an error: {ex.Message}");
}
finally
{
// Always release the semaphore, even if an error occurs.
_semaphore.Release();
Console.WriteLine($"Task {taskId} has released semaphore.");
}
}
}
Imports IronPdf
Imports System
Imports System.Threading
Imports System.Threading.Tasks
Friend Class Program
Private Shared _semaphore As New SemaphoreSlim(3)
Shared Async Function Main(ByVal args() As String) As Task
Dim tasks = New Task(2){}
For i As Integer = 0 To tasks.Length - 1
Dim content As String = $"<h1>Document {i}</h1><p>Content for PDF {i}.</p>"
Dim path As String = $"safe_output_{i}.pdf"
' Start multiple tasks to demonstrate deadlock-free semaphore usage.
tasks(i) = SafePdfTaskAsync(content, path, i)
Next i
Await Task.WhenAll(tasks) ' Wait for all tasks to finish.
End Function
' Method demonstrating best practices for using SemaphoreSlim to avoid deadlocks.
Public Shared Async Function SafePdfTaskAsync(ByVal content As String, ByVal path As String, ByVal taskId As Integer) As Task
Console.WriteLine($"Task {taskId} is waiting to generate PDF...")
' Wait to enter the semaphore.
Await _semaphore.WaitAsync()
Try
Console.WriteLine($"Task {taskId} is generating PDF.")
Dim renderer = New ChromePdfRenderer()
Dim pdf = Await renderer.RenderHtmlAsPdfAsync(content) ' Render HTML to PDF
pdf.SaveAs(path) ' Save the PDF
Console.WriteLine($"Task {taskId} has completed PDF generation.")
Catch ex As Exception
Console.WriteLine($"Task {taskId} encountered an error: {ex.Message}")
Finally
' Always release the semaphore, even if an error occurs.
_semaphore.Release()
Console.WriteLine($"Task {taskId} has released semaphore.")
End Try
End Function
End Class
通過使用 try-catch-finally
區塊,我們確保即使拋出異常,SemaphoreSlim 對象也能總是被釋放,從而防止死鎖。 透過記錄錯誤和適當管理信號量釋放,我們可以保持程式穩定並防止任何意外行為。
正如您在下面的輸出圖像中所見,我嘗試讓程序加載不存在的HTML文件以模擬錯誤,但即便出現此錯誤,程序仍然打印錯誤信息告訴我出了什麼問題,然後繼續使用finally區塊釋放信號量。
IronPDF旨在有效地處理並發PDF處理任務,提供優於許多其他PDF庫的性能和可靠性。 其穩健的架構使其能夠隨著應用程式的需求進行擴展,非常適合高需求的環境。 與其他 PDF 函式庫在性能、易用性和穩健性標準上進行比較時,IronPDF 展現了強大的競爭力。 為了展示這一點,我將IronPDF與其他幾個流行的PDF庫進行了比較,如iTextSharp、PDFsharp、DinkToPdf和EvoPDF:
IronPDF:
非同步操作:支援非同步 PDF 生成,允許在回應性至關重要的網路應用程式中具有更好的性能。
iTextSharp:
資源管理:使用 iTextSharp 時,記憶體使用量可能較高,特別是在處理大型文件或複雜操作時,可能導致某些情況下的效能瓶頸。
PDFsharp:
資源管理:它在記憶體使用方面的優化程度較低,可能在處理包含大量圖片的大型檔案或文件時遇到困難。
DinkToPdf:
資源管理:這通常需要大量的記憶體和處理能力,並且缺乏對非同步操作的原生支持,限制了其在高負載情境下的性能。
EvoPDF:
IronPDF:
安裝和整合:通過 NuGet 簡單安裝,並可順利整合到現有的 .NET 專案中,只需最低限度的配置。
iTextSharp:
安裝與整合:可透過 NuGet 取得,但需要對 API 有更深入的理解才能有效整合。
PDFsharp:
安裝和整合:通過 NuGet 安裝非常容易,但提供的 HTML 轉 PDF 功能有限。
DinkToPdf:
安裝和整合: 安裝可能比較複雜,需要像 wkhtmltopdf 這樣的額外依賴,這可能會使設置變得複雜。
EvoPDF:
IronPDF:
相容性:完全相容於 .NET Core、.NET 5+ 和舊版 .NET Framework,使其可靈活運用於不同類型的專案。
iTextSharp:
相容性:適用於多種環境,包括.NET Framework和.NET Core。
PDFsharp:
兼容性: 兼容 .NET Framework 和 .NET Core,但擁有有限的高級功能。
DinkToPdf:
相容性:適用於 .NET Core 和 .NET Framework,但需要外部依賴項,這可能會引入相容性問題。
EvoPDF:
IronPDF 無縫整合非同步程式設計模型,補充像 SemaphoreSlim 之類的並發控制機制。 這使開發者能夠以最少的努力構建響應迅速且性能友好的應用程式。
IronPDF 也提供廣泛的文件和支援資源,以幫助開發人員理解和實施有效的錯誤處理慣例。 這種全面的支持對於在 .NET 項目中進行故障排除和優化 PDF 操作具有很大價值。
IronPDF 提供:
PDF API 參考: 提供 API 參考資料,讓您可以充分利用我們工具的所有功能。
如需更多資訊,請查看 IronPDF 的詳盡文件。
在 .NET 應用程式中使用 SemaphoreSlim 進行並發管理是至關重要的,特別是在處理像 PDF 處理這樣的資源密集型任務時。 通過將 SemaphoreSlim 與 IronPDF 集成,開發人員可以實現安全、高效且可靠的併發控制,確保其應用程式保持響應性並具有良好的性能。
探索 IronPDF 如何簡化您的 PDF 處理工作流程。 試試看它的免費試用,如果想要在項目中繼續使用這款強大的工具,價格從$749起。