在生产环境中测试,无水印。
随时随地满足您的需求。
获得30天的全功能产品。
几分钟内就能启动并运行。
在您的产品试用期间,全面访问我们的支持工程团队。
并发管理是 C# 中高性能应用程序的一个重要方面。 它可以确保资源得到有效利用,同时避免潜在的冲突或性能瓶颈,因此有一个轻量级的信号控制访问会非常有帮助。 这就是 SemaphoreSlim 发挥作用的地方。 SemaphoreSlim 是一种轻量级同步原语,用于控制资源访问,最终防止出现竞赛条件并确保线程安全。
那么,如果您想将其与管理 PDF 生成流程的 PDF 库一起实施呢? 您可能正在寻找一个强大的PDF库,这时IronPDF就派上用场了。 IronPDF 是面向 .NET 开发人员的强大的 PDF 生成和处理库,在多线程环境中使用时可极大地受益于并发管理。
如果您想了解SemaphoreSlim和IronPDF的实际应用,请务必继续阅读,我们将探讨使用SemaphoreSlim的好处,以及如何将其与IronPDF集成,以安全地处理并发操作、提高性能并确保可靠的PDF处理。
SemaphoreSlim 是 .NET 中的一种同步原语,用于限制可以并发访问特定资源或资源池的线程数量。 它是完整 Semaphore 类的轻量级版本,设计用于在只需使用更简单、更快速的 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
在程序运行过程中,当所有可用许可都已被线程获取时,线程的 Semaphore 计数可能会动态为零。 此状态表示已达到允许的最大并发访问量。
如果您愿意,可以设置线程的初始数目和最大数目,初始信号量计数从零开始,然后使用一个单独的初始化任务在资源就绪时增加信号量计数,从而允许您选择的线程数继续进行。 当信号量计数为零时,线程将会在尝试进入信号量时等待,这被称为“阻塞等待”。
您可以跟踪先前的信号量计数,以根据先前的计数调整信号量的行为。 然后您可以相应地操作信号量(例如,通过释放或等待)。 随着线程的释放,semaphore 的数量也会减少。
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()
方法进入信号量,并在finally块中使用Release()
以确保即使发生异常也始终释放信号量。 控制台输出日志会显示每个任务开始、完成和释放信号的时间,这样您就可以跟踪并发行为。
当多个线程与共享资源交互时,线程安全至关重要。 在 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 生成任务压垮。 这种方法有助于更均匀地分配工作量,提高应用程序的整体性能和稳定性。
如果不能正确释放 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
通过使用try-catch-finally
块,我们确保了即使抛出异常,也始终释放SemaphoreSlim对象,从而防止死锁。 通过记录错误和正确管理信号释放,我们可以保持程序稳定,防止出现任何意外行为。
正如您在下面的输出图像中看到的,我通过尝试让程序加载一个不存在的 HTML 文件来模拟错误,但即使出现了这样的错误,程序也会打印错误信息,告诉我出了什么问题,然后继续使用 finally 块释放信号。
IronPDF 设计用于高效处理并发 PDF 处理任务,其性能和可靠性优于许多其他 PDF 库。 其强大的架构可根据应用程序的需求进行扩展,是高需求环境的理想选择。 在性能、易用性和稳健性等标准上进行比较时,IronPDF 被证明是一个强大的竞争者。 为了展示这一点,我将 IronPDF 与其他几个流行的 PDF 库进行了比较,如 iTextSharp、PDFsharp、DinkToPdf 和 EvoPDF:
IronPDF:
异步操作:支持异步 PDF 生成,可以在响应性至关重要的 Web 应用程序中提高性能。
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起。