AYUDA .NET

C# Semaphoreslim (Cómo funciona para desarrolladores)

Publicado en 23 de octubre, 2024
Compartir:

Introducción

La gestión de la concurrencia es un aspecto crítico de las aplicaciones de alto rendimiento en C#. Garantiza que los recursos se utilicen de forma eficiente evitando posibles conflictos o cuellos de botella en el rendimiento, por lo que disponer de un semáforo ligero que controle el acceso puede ser muy útil. Aquí es dondeSemaphoreSlim entra en juego. SemaphoreSlim es una primitiva de sincronización ligera que controla el acceso a los recursos, evitando en última instancia las condiciones de carrera y garantizando la seguridad de los hilos.

¿Y si quisieras implementar esto junto con una biblioteca PDF para gestionar los procesos de generación de PDF? Es posible que esté buscando una potente biblioteca PDF, en la queIronPDF entra. IronPDF es una robusta biblioteca de generación y manipulación de PDF para desarrolladores .NET que puede beneficiarse enormemente de la gestión de concurrencia cuando se utiliza en entornos multihilo.

Si desea ver SemaphoreSlim y IronPDF en acción, asegúrese de seguir leyendo mientras exploramos los beneficios de usar SemaphoreSlim y cómo integrarlo con IronPDF para manejar con seguridad las operaciones concurrentes, mejorar el rendimiento y garantizar un procesamiento fiable de PDF.

Comprensión de SemaphoreSlim en C#

¿Qué es SemaphoreSlim?

SemaphoreSlim es una primitiva de sincronización de .NET que limita el número de subprocesos que pueden acceder simultáneamente a un determinado recurso o conjunto de recursos. Se trata de una versión ligera de la clase Semaphore completa, diseñada para funcionar de forma más eficiente en situaciones en las que basta con un semáforo más sencillo y rápido.

Algunas ventajas de utilizar SemaphoreSlim son que la sobrecarga del sistema se reduce en comparación con Semaphore, es ideal para gestionar recursos limitados(como conexiones a bases de datos o acceso a archivos)además, es compatible con métodos de espera asíncronos, por lo que se adapta bien a los modernos patrones de programación asíncronos/de espera.

Ejemplo de código de uso básico de 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#

Durante el funcionamiento de un programa, la cuenta del semáforo puede llegar dinámicamente a cero hilos cuando todos los permisos disponibles han sido adquiridos por hilos. Este estado indica que se ha alcanzado el máximo de accesos concurrentes permitidos.

Si lo desea, puede establecer el número inicial y máximo de subprocesos, comenzando el recuento inicial de semáforos en cero y luego utilizando una tarea de inicialización separada que aumente el recuento de semáforos cuando el recurso esté listo, permitiendo que el número de subprocesos que elija continúe. Cuando el recuento de semáforos es cero, los hilos esperarán cuando su intento de entrar en el semáforo, esto se conoce como "bloque de espera".

Podría hacer un seguimiento del recuento anterior del semáforo para ajustar el comportamiento del semáforo en función del recuento anterior, a continuación, puede manipular el semáforo en consecuencia(por ejemplo, liberando o esperando). A medida que los hilos se liberan, el número de semáforos disminuye.

Salida de la consola

C# Semaphoreslim(Cómo funciona para desarrolladores): Figura 1

Casos de uso comunes para SemaphoreSlim

Algunos casos de uso comunes para SemaphoreSlim son:

  • Limitar el acceso a bases de datos o sistemas de archivos: Evita abrumar estos recursos con demasiadas peticiones concurrentes.
  • Gestión de grupos de hilos: Puede utilizarse para controlar el número de hilos que realizan una operación concreta, mejorando la estabilidad y el rendimiento.

Uso de SemaphoreSlim con IronPDF para una concurrencia segura

Configuración de IronPDF en un entorno multihilo

Para empezar a utilizar IronPDF en un entorno multihilo, instale la aplicaciónPaquete NuGet IronPDF. Para ello, vaya a herramientas > NuGet Package Manager > NuGet Package Manager for Solution y busque IronPDF:

C# Semaphoreslim(Cómo funciona para desarrolladores): Figura 2

También puede ejecutar el siguiente comando en la consola del gestor de paquetes:

Install-Package IronPdf
Install-Package IronPdf
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'Install-Package IronPdf
VB   C#

Para empezar a utilizar IronPDF en su código, asegúrese de que ha colocado la declaración "using IronPdf" en la parte superior de su archivo de código. Para obtener una guía más detallada sobre la configuración de IronPDF en su entorno, consulte su sitio webcómo empezar página.

Control de acceso a la generación de PDF con SemaphoreSlim

Si utiliza SemaphoreSlim, podrá controlar eficazmente el acceso a las tareas de generación de PDF. Esto garantiza que su aplicación no intente generar demasiados PDF simultáneamente, lo que podría afectar al rendimiento o provocar fallos.

El siguiente código de ejemplo demuestra el uso básico de SemaphoreSlim con 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#

En este ejemplo, primero inicializamos SemaphoreSlim y establecemos el recuento inicial y máximo de SemaphoreSlim en '2', limitándolo a dos generaciones de PDF concurrentes. A continuación, creamos una matriz de tareas que se utiliza para controlar el número de tareas que el programa tiene que hacer, después de lo cual utilizamos un bucle for para crear dinámicamente PDFs basados en el número de tareas dentro de la matriz de tareas.

El *WaitAsync()a continuación, se utiliza el método *` para entrar en el semáforo, y `Release()` se utiliza en el bloque finally para garantizar que el semáforo se libera siempre, incluso si se produce una excepción. Los registros de salida de la consola muestran cuando cada tarea comienza, termina y libera el semáforo, esto le permite realizar un seguimiento del comportamiento de la concurrencia.

Consola de salida

C# Semaphoreslim(Cómo funciona para desarrolladores): Figura 3

Archivos PDF de salida

C# Semaphoreslim(Cómo funciona para desarrolladores): Figura 4

Garantizar la seguridad de los subprocesos en las tareas de manipulación de PDF

La seguridad de los subprocesos es crucial cuando varios subprocesos interactúan con recursos compartidos. En la manipulación de PDF, SemaphoreSlim garantiza que sólo un número definido de subprocesos pueda modificar PDF simultáneamente, evitando condiciones de carrera y asegurando la coherencia. En el siguiente código, estamos simulando un escenario en el que estamos añadiendo una marca de agua a múltiples PDFs mientras nos aseguramos de que sólo se produce una operación a la vez.

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#

Estableciendo el recuento de semáforos a 1 usando **private static SemaphoreSlim _semaphore = new SemaphoreSlim(1)|**, nos aseguramos de que sólo una tarea pueda manipular PDFs a la vez.

Salida de la consola

C# Semaphoreslim(Cómo funciona para desarrolladores): Figura 5

Optimización del rendimiento con SemaphoreSlim y IronPDF

Gestión de operaciones con uso intensivo de recursos

IronPDF destaca en la gestión de tareas que consumen muchos recursos, como la conversión de grandes archivos HTML a PDF, y sobresale en la realización de estas tareas en un entorno asíncrono. El uso de SemaphoreSlim para gestionar estas operaciones garantiza que su aplicación siga respondiendo sin perder rendimiento, incluso bajo cargas pesadas.

El siguiente código de ejemplo muestra un escenario en el que necesitamos limitar el número de conversiones simultáneas de HTML a PDF de gran tamaño para evitar sobrecargar los recursos del sistema.

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#

Cuando se trata de tareas que consumen muchos recursos, como la conversión de grandes archivos HTML a PDF, SemaphoreSlim puede ayudar a equilibrar la carga y optimizar el uso de los recursos. Al establecer un límite de 2 operaciones simultáneas, evitamos que el sistema se vea desbordado por tareas de generación de PDF que consumen muchos recursos. Este enfoque ayuda a distribuir la carga de trabajo de manera más uniforme, mejorando el rendimiento y la estabilidad de la aplicación en general.

Imagen de salida: Archivos generados con este método

C# Semaphoreslim(Cómo funciona para desarrolladores): Figura 6

Evitar bloqueos en la gestión de la concurrencia

Pueden producirse bloqueos si los semáforos no se liberan correctamente. Una buena práctica a tener en cuenta es el uso de bloques try-finally para asegurarse de que los semáforos se liberan incluso si se produce una excepción, evitando bloqueos y manteniendo su aplicación funcionando sin problemas. Algunas de las mejores prácticas para evitar bloqueos incluyen liberar siempre el semáforo en el bloque finally, y evitar el uso de llamadas de bloqueo como `.wait()\El código asíncrono se traduce como "resultado" dentro de su código asíncrono.

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#

Mediante el uso de un bloque "try-catch-finally", nos hemos asegurado de que el objeto SemaphoreSlim siempre se libera, incluso si se lanza una excepción, evitando así los bloqueos. Mediante el registro de errores y la gestión adecuada de la liberación de semáforos podemos mantener el programa estable y evitar cualquier comportamiento inesperado.

Como se puede ver en la imagen de salida de abajo, he simulado un error al intentar que el programa cargue un archivo HTML que no existe, pero incluso con este error, el programa imprime el mensaje de error que me dice lo que salió mal y luego procede a liberar el semáforo utilizando el bloque finally.

C# Semaphoreslim(Cómo funciona para desarrolladores): Figura 7

Ventajas del uso de IronPDF para el procesamiento concurrente de PDF

Procesamiento de PDF eficaz y fiable

IronPDF se ha diseñado para gestionar eficazmente tareas de procesamiento de PDF concurrentes, ofreciendo un rendimiento y una fiabilidad superiores a los de muchas otras bibliotecas de PDF. Su sólida arquitectura le permite escalar con las necesidades de su aplicación, por lo que es ideal para entornos de alta demanda. Cuando se compara con otras bibliotecas PDF en función de criterios de rendimiento, facilidad de uso y solidez, IronPDF demuestra ser un fuerte competidor. Para demostrarlo, he comparado IronPDF con otras bibliotecas de PDF populares como iTextSharp, PDFsharp, DinkToPdf y EvoPDF:

1. **Rendimiento

IronPDF:

  • Velocidad de renderizado: IronPDF es conocido por su capacidad de renderizado rápido y eficiente, especialmente al convertir HTML a PDF. Utiliza el renderizado basado en Chrome, que proporciona una alta fidelidad al contenido HTML original, incluida la ejecución de CSS y JavaScript.
  • Gestión de recursos: IronPDF está optimizada para gestionar archivos PDF grandes y complejos con un menor uso de memoria en comparación con otras bibliotecas, lo que la hace adecuada para aplicaciones de gran volumen.
  • Operaciones asíncronas: Admite la generación asíncrona de PDF, lo que permite un mejor rendimiento en aplicaciones web en las que la capacidad de respuesta es crucial.

    iTextSharp:

  • Velocidad de renderizado: iTextSharp ofrece un buen rendimiento para PDF con mucho texto, pero puede ralentizarse considerablemente con diseños complejos o imágenes.
  • Gestión de recursos: El uso de memoria puede ser mayor con iTextSharp, especialmente cuando se manejan documentos grandes o manipulaciones complejas, lo que provoca cuellos de botella en el rendimiento en algunos casos.

    PDFsharp:

  • Velocidad de renderizado: PDFsharp es generalmente más lento en comparación con IronPDF cuando se trata de diseños complejos o cuando se convierte desde HTML, ya que carece de un motor de renderizado HTML nativo.
  • Gestión de recursos: Está menos optimizado para el uso de memoria y puede tener problemas con archivos grandes o documentos que contengan numerosas imágenes.

    DinkToPdf:

  • Velocidad de renderizado: DinkToPdf utiliza el motor wkhtmltopdf, que es eficaz para conversiones básicas de HTML a PDF, pero puede tener problemas con contenidos más complejos o dinámicos.
  • Gestión de recursos: A menudo requiere una memoria y una potencia de procesamiento significativas, y carece de soporte nativo para operaciones asíncronas, lo que limita su rendimiento en escenarios de alta carga.

    EvoPDF:

  • Velocidad de renderizado: EvoPDF también proporciona renderizado basado en Chrome como IronPDF, ofreciendo un buen rendimiento, especialmente para conversiones de HTML a PDF.
  • Gestión de recursos: Está bien optimizado, pero aún así puede consumir más recursos en comparación con IronPDF en algunos escenarios debido a optimizaciones menos agresivas.

2. **Facilidad de uso

IronPDF:

  • Diseño de API: IronPDF ofrece una API moderna e intuitiva que es fácil de usar para desarrolladores de todos los niveles. La biblioteca está diseñada para funcionar a la perfección con aplicaciones .NET, lo que la convierte en una gran opción para los desarrolladores de C#.
  • Documentación y soporte: Una documentación exhaustiva, un gran número de ejemplos de código y un excelente soporte al cliente facilitan la puesta en marcha y la rápida resolución de problemas.
  • Instalación e integración: Se instala fácilmente a través de NuGet y se integra sin problemas en los proyectos .NET existentes, requiriendo una configuración mínima.

    iTextSharp:

  • Diseño de la API: iTextSharp tiene una curva de aprendizaje pronunciada, con una API más compleja que puede resultar abrumadora para los principiantes. Su flexibilidad se consigue a costa de la simplicidad.
  • Documentación y soporte: Aunque está bien documentado, las amplias opciones de configuración pueden dificultar la búsqueda de ejemplos sencillos para tareas comunes.
  • Instalación e integración: Disponible a través de NuGet, pero requiere un conocimiento más profundo de la API para integrarse eficazmente.

    PDFsharp:

  • Diseño de la API: PDFsharp está diseñado para ser sencillo en tareas básicas de PDF, pero carece de funciones avanzadas, lo que puede limitar su uso en situaciones más complejas.
  • Documentación y soporte: Existe documentación básica, pero es menos extensa y carece de ejemplos detallados de uso avanzado en comparación con IronPDF.
  • Instalación e integración: Fácil de instalar a través de NuGet, pero ofrece una funcionalidad limitada de HTML a PDF.

    DinkToPdf:

  • Diseño de la API: La API de DinkToPdf es relativamente sencilla pero menos pulida que la de IronPDF. Se dirige principalmente a la conversión de HTML a PDF y ofrece menos funciones para la manipulación directa de PDF.
  • Documentación y soporte: La documentación es limitada, y el soporte de la comunidad no es tan robusto como el de otras bibliotecas, lo que dificulta la resolución de problemas.
  • Instalación e integración: Puede ser más complejo de instalar, ya que requiere dependencias adicionales como wkhtmltopdf, lo que puede complicar la configuración.

    EvoPDF:

  • Diseño de API: EvoPDF proporciona una API sencilla similar a IronPDF, centrada en gran medida en la conversión de HTML a PDF con la facilidad de uso en mente.
  • Documentación y soporte: Bien documentado con buenas opciones de soporte, pero no tan extenso en ejemplos impulsados por la comunidad como IronPDF.
  • Instalación e integración: Fácil de integrar en proyectos .NET con los paquetes NuGet disponibles.

3. **Solidez

IronPDF:

  • Conjunto de funciones: IronPDF es muy robusto y admite una amplia gama de funciones, como la conversión de HTML a PDF, la edición de PDF, la extracción de texto, el cifrado, las anotaciones y las firmas digitales.
  • Gestión de errores: Ofrece una sólida gestión de errores y excepciones, lo que la hace fiable para entornos de producción.
  • Compatibilidad: Totalmente compatible con .NET Core, .NET 5+ y las versiones anteriores de .NET Framework, lo que lo hace versátil para diferentes tipos de proyectos.

    iTextSharp:

  • Conjunto de características: iTextSharp es extremadamente robusto y cuenta con un amplio conjunto de características que soportan casi cualquier tarea PDF, incluyendo manipulaciones complejas y manejo de formularios.
  • Manejo de errores: Buen manejo de errores pero puede ser complejo de manejar debido a las complejidades de la librería.
  • Compatibilidad: Adecuado para una amplia gama de entornos, incluidos .NET Framework y .NET Core.

    PDFsharp:

  • Conjunto de funciones: Funciones básicas de creación y manipulación de PDF. Carece de algunas funciones avanzadas como la conversión de HTML a PDF y la edición de documentos más sofisticados.
  • Manejo de errores: Manejo básico de errores; es menos fiable en escenarios complejos en comparación con bibliotecas más robustas como IronPDF.
  • Compatibilidad: Compatible con .NET Framework y .NET Core, pero con funcionalidad avanzada limitada.

    DinkToPdf:

  • Conjunto de características: Principalmente centrado en HTML a PDF. Limitado en términos de manipulación directa de PDF y carece de funciones avanzadas como anotaciones y manejo de formularios.
  • Manejo de errores: Manejo básico de errores; propensos a los bloqueos o cuelgues en HTML complejo o archivos de gran tamaño.
  • Compatibilidad: Funciona con .NET Core y .NET Framework pero requiere dependencias externas, lo que puede introducir problemas de compatibilidad.

    EvoPDF:

  • Conjunto de características: Ofrece un sólido conjunto de características similares a IronPDF, incluyendo conversiones avanzadas de HTML a PDF y algunas capacidades de manipulación de documentos.
  • Gestión de errores: Gestión de errores sólida y rendimiento fiable en entornos de producción.
  • Compatibilidad: Totalmente compatible con .NET Core, .NET Framework y las versiones más recientes de .NET, lo que lo hace versátil y fiable.

Resumen

  • Rendimiento: IronPDF y EvoPDF lideran en rendimiento gracias a sus motores de renderizado basados en Chrome, mientras que iTextSharp y PDFsharp pueden quedarse atrás en el manejo de documentos complejos.
  • Facilidad de uso: IronPDF destaca por su API intuitiva y su extensa documentación, lo que lo hace accesible para todos los niveles de desarrolladores. iTextSharp ofrece potencia a costa de simplicidad, mientras que DinkToPdf y PDFsharp son más sencillas pero menos completas.
  • Robustez: IronPDF e iTextSharp proporcionan los conjuntos de características más robustos, con IronPDF ofreciendo una integración más simple y características modernas como el soporte async, mientras que iTextSharp cubre casos de uso más especializados con una curva de aprendizaje más pronunciada.

Soporte integral para programación asíncrona

IronPDF se integra perfectamente conasync el objetivo de la traducción es explicar las características y ventajas de estas herramientas para desarrolladores. De este modo, los desarrolladores podrán crear aplicaciones eficaces y de alto rendimiento con el mínimo esfuerzo.

IronPDF también ofrece una amplia documentación y recursos de apoyo que ayudan a los desarrolladores a comprender y aplicar prácticas eficaces de gestión de errores. Esta completa ayuda es valiosa para solucionar problemas y optimizar las operaciones con PDF en proyectos .NET.

IronPDF ofrece:

  • Documentación completa: Documentación extensa y fácil de usar que cubre todas las funciones.
  • Asistencia 24/5 horas: Asistencia técnica activa disponible.
  • Videotutoriales: En YouTube hay disponibles guías de vídeo paso a paso.
  • Foro comunitario: Comunidad comprometida para apoyo adicional.
  • Referencia API de PDF: Ofrece referencias de API para que puedas aprovechar al máximo lo que nuestras herramientas tienen para ofrecer.

    Para obtener más información, consulte la extensa documentación de IronPDF.documentación.

Conclusión

El uso de SemaphoreSlim para la gestión de la concurrencia en aplicaciones .NET es crucial, especialmente cuando se trata de tareas que consumen muchos recursos, como el procesamiento de PDF. Mediante la integración de SemaphoreSlim con IronPDF, los desarrolladores pueden lograr un control de concurrencia seguro, eficiente y fiable, garantizando que sus aplicaciones sigan siendo sensibles y de fácil rendimiento.

Descubra cómo IronPDF puede agilizar sus flujos de trabajo de procesamiento de PDF. Pruébelo usted mismo con suprueba gratuita desde solo 749 $ si quieres mantener esta potente herramienta en tus proyectos.

C# Semaphoreslim(Cómo funciona para desarrolladores): Figura 8

< ANTERIOR
Palabra clave C# Init (Cómo funciona para desarrolladores)
SIGUIENTE >
C# try catch finally (Cómo funciona para desarrolladores)

¿Listo para empezar? Versión: 2024.12 acaba de salir

Descarga gratuita de NuGet Descargas totales: 11,622,374 Ver licencias >