.NET 帮助

C# Semaphoreslim(如何为开发人员工作)

发布 2024年十月23日
分享:

介绍

并发管理是 C# 中高性能应用程序的一个重要方面。 它可以确保资源得到有效利用,同时避免潜在的冲突或性能瓶颈,因此有一个轻量级的信号控制访问会非常有帮助。 这就是SemaphoreSlim开始发挥作用。 SemaphoreSlim 是一种轻量级同步原语,用于控制资源访问,最终防止出现竞赛条件并确保线程安全。

那么,如果您想将其与管理 PDF 生成流程的 PDF 库一起实施呢? 您可能正在寻找一个功能强大的 PDF 库,其中包括IronPDF登场。 IronPDF 是面向 .NET 开发人员的强大的 PDF 生成和处理库,在多线程环境中使用时可极大地受益于并发管理。

如果您想了解SemaphoreSlim和IronPDF的实际应用,请务必继续阅读,我们将探讨使用SemaphoreSlim的好处,以及如何将其与IronPDF集成,以安全地处理并发操作、提高性能并确保可靠的PDF处理。

理解 C# 中的 SemaphoreSlim;

什么是 SemaphoreSlim?

SemaphoreSlim 是 .NET 中的一种同步原语,用于限制可以并发访问特定资源或资源池的线程数量。 它是完整 Semaphore 类的轻量级版本,设计用于在只需使用更简单、更快速的 Semaphore 的情况下更高效地工作。

使用 SemaphoreSlim 的一些优势包括:与 Semaphore 相比,系统开销减少,是管理有限资源的理想选择(例如数据库连接或文件访问)该工具支持.NET、Java、Python 或 Node js,并且支持异步等待方法,因此非常适合现代异步/等待编程模式。

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#

在程序运行过程中,当所有可用许可都已被线程获取时,线程的 Semaphore 计数可能会动态为零。 此状态表示已达到允许的最大并发访问量。

如果您愿意,可以设置初始线程数和最大线程数,将初始寄存器计数从 0 开始,然后使用单独的初始化任务,在资源准备就绪时增加寄存器计数,允许您选择的线程数继续运行。 当 semaphore 的计数为零时,线程在尝试进入 semaphore 时会等待,这被称为 "块等待"。

您可以跟踪之前的寄存器计数,以便根据之前的计数调整寄存器的行为,然后可以相应地操作寄存器(例如,通过发布或等待). 随着线程的释放,semaphore 的数量也会减少。

控制台输出

C# Semaphoreslim(如何为开发人员工作):图 1

SemaphoreSlim 的常见使用案例

SemaphoreSlim 的一些常见使用案例包括

  • 限制对数据库或文件系统的访问: 它可以防止过多的并发请求使这些资源不堪重负。
  • 管理线程池: 可用于控制执行特定操作的线程数量,从而提高稳定性和性能。

使用 SemaphoreSlim 和 IronPDF 实现安全并发

在多线程环境中设置 IronPDF

要开始在多线程环境中使用 IronPDF,首先要安装IronPDF NuGet 软件包. 您可以通过导航至工具 > NuGet Package Manager > NuGet Package Manager for Solution 并搜索 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 的更深入指南,请查阅其入门page.

使用 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#

通过使用 `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;
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

避免并发管理中的死锁

如果不能正确释放 Semaphores,就会出现死锁。 需要牢记的一个良好做法是使用 try-finally 块,以确保即使出现异常也能释放 semaphores,从而防止死锁并保持应用程序的流畅运行。 避免死锁需要记住的一些最佳实践包括:始终在 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:

  • 渲染速度: 与 IronPDF 相比,PDFsharp 在处理复杂布局或从 HTML 转换时通常较慢,因为它缺乏本地 HTML 渲染引擎。
  • 资源管理: 对内存使用的优化程度较低,在处理大文件或包含大量图片的文档时可能会遇到困难。

    DinkToPdf:

  • 渲染速度: DinkToPdf 使用的是 wkhtmltopdf 引擎,该引擎对于基本的 HTML 到 PDF 转换非常有效,但在处理更复杂或动态的内容时可能会比较吃力。
  • 资源管理: 通常需要大量内存和处理能力,并且缺乏对异步操作的本地支持,从而限制了其在高负载场景下的性能。

    EvoPDF:

  • 渲染速度: EvoPDF 也像 IronPDF 一样提供基于 Chrome 浏览器的渲染,提供良好的性能,尤其是 HTML 到 PDF 的转换。
  • 资源管理: 优化良好,但由于优化不够积极,在某些情况下可能仍会比 IronPDF 消耗更多资源。

2. 易用性

IronPDF:

  • API 设计: IronPdf 提供现代、直观的 API,便于各种技能水平的开发人员使用。 该库旨在与 .NET 应用程序无缝协作,是 C# 开发人员的最佳选择。
  • 文档和支持: 全面的文档、大量的代码示例和出色的客户支持使您能够轻松上手并快速解决问题。
  • 安装和集成: 可通过 NuGet 轻松安装,并可顺利集成到现有的 .NET 项目中,只需极少的配置。

    iTextSharp:

  • 应用程序接口设计: iTextSharp 的学习曲线较陡峭,其应用程序接口较为复杂,初学者可能会不知所措。 其灵活性是以简单为代价的。
  • 文档和支持: 虽然文档详尽,但由于配置选项繁多,因此很难找到常见任务的直接示例。
  • 安装和集成: 通过 NuGet 提供,但需要深入了解 API 才能有效集成。

    PDFsharp:

  • API 设计: PDFsharp 的设计简单,适用于基本的 PDF 任务,但缺乏开箱即用的高级功能,这可能会限制其在更复杂场景中的使用。
  • Documentation and Support: 提供基本的文档,但与 IronPDF 相比,其内容较少,而且缺乏详细的高级用法示例。
  • 安装和集成: 通过 NuGet 安装简单,但提供有限的 HTML 转 PDF 功能。

    DinkToPdf:

  • API 设计: 与 IronPDF 相比,DinkToPdf 的 API 相对简单,但不够精致。 它主要针对 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 等更强大的库相比,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 无缝集成了异步这些工具包括:.NET、Java、Python 或 Node.js 编程模型、并发控制机制(如 SemaphoreSlim)的补充。 这样,开发人员就能以最小的工作量构建响应迅速、性能友好的应用程序。

IronPdf 还提供广泛的文档和支持资源,帮助开发人员了解并实施有效的错误处理实践。 这种全面的支持对于在 .NET 项目中排除故障和优化 PDF 操作非常有价值。

IronPDF 提供:

  • 全面的文档:涵盖所有功能的广泛且用户友好的文档。
  • 24/5 支持:提供活跃的工程师支持。
  • 视频教程:详细的视频指南可在YouTube上找到。
  • 社区论坛:为了提供额外支持而设立的活跃社区。
  • PDF API 参考: 提供 API 参考,让您充分利用我们的工具所提供的功能。

    如需更多信息,请查看IronPDF的广泛内容。文档.

结论

在.NET应用程序中使用SemaphoreSlim进行并发管理至关重要,尤其是在处理PDF处理等资源密集型任务时。 通过将SemaphoreSlim与IronPdf集成,开发人员可以实现安全、高效、可靠的并发控制,确保其应用程序保持响应速度快、性能友好。

了解 IronPDF 如何简化您的 PDF 处理工作流程。 使用其免费试用如果您想在您的项目中继续使用这一强大的工具,请联系我们。

C# Semaphoreslim(如何为开发人员工作):图 8

< 前一页
C# Init 关键字(如何为开发人员工作)
下一步 >
C# try catch finally(开发人员如何使用它)

准备开始了吗? 版本: 2024.12 刚刚发布

免费NuGet下载 总下载量: 11,781,565 查看许可证 >