using IronPdf;
// Disable local disk access or cross-origin requests
Installation.EnableWebSecurity = true;
// Instantiate Renderer
var renderer = new ChromePdfRenderer();
// Create a PDF from a HTML string using C#
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1>");
// Export to a file or Stream
pdf.SaveAs("output.pdf");
// Advanced Example with HTML Assets
// Load external html assets: Images, CSS and JavaScript.
// An optional BasePath 'C:\site\assets\' is set as the file location to load assets from
var myAdvancedPdf = renderer.RenderHtmlAsPdf("<img src='icons/iron.png'>", @"C:\site\assets\");
myAdvancedPdf.SaveAs("html-with-assets.pdf");
C# Semaphoreslim (Comment ça marche pour les développeurs)
Chaknith Bin
octobre 23, 2024
Partager:
Introduction
La gestion de la concurence est un aspect essentiel des applications performantes en C#. Il permet de s'assurer que les ressources sont utilisées efficacement tout en évitant les conflits potentiels ou les goulots d'étranglement au niveau des performances, c'est pourquoi il peut être très utile de disposer d'un sémaphore léger qui contrôle l'accès. C'est là que SemaphoreSlim entre en jeu. SemaphoreSlim est une primitive de synchronisation légère qui contrôle l'accès aux ressources, ce qui permet d'éviter les conditions de course et d'assurer la sécurité des threads.
Que se passerait-il si vous vouliez mettre cela en œuvre avec une bibliothèque PDF pour gérer les processus de génération de PDF ? Vous pourriez être à la recherche d'une bibliothèque PDF puissante, où IronPDF entre en jeu. IronPDF est une bibliothèque robuste de génération et de manipulation de PDF pour les développeurs .NET qui peut grandement bénéficier de la gestion des concurrences lorsqu'elle est utilisée dans des environnements multithreads.
Si vous souhaitez voir SemaphoreSlim et IronPDF en action, ne manquez pas de lire la suite pour découvrir les avantages de l'utilisation de SemaphoreSlim et comment l'intégrer à IronPDF pour gérer en toute sécurité les opérations simultanées, améliorer les performances et garantir un traitement fiable des PDF.
Comprendre SemaphoreSlim dans C# ;
Qu'est-ce que SemaphoreSlim ?
SemaphoreSlim est une primitive de synchronisation dans .NET qui limite le nombre de threads pouvant accéder simultanément à une ressource particulière ou à un pool de ressources. Il s'agit d'une version allégée de la classe Sémaphore complète, conçue pour fonctionner plus efficacement dans les situations où un sémaphore plus simple et plus rapide est suffisant.
Certains avantages de l'utilisation de SemaphoreSlim sont que la surcharge du système est réduite par rapport à Semaphore, il est idéal pour gérer des ressources limitées (comme les connexions à une base de données ou l'accès à des fichiers), et il prend en charge les méthodes d'attente asynchrones, ce qui le rend bien adapté aux modèles de programmation modernes async/await.
Exemple de code d'une utilisation basique 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
$vbLabelText $csharpLabel
Au cours de l'exécution d'un programme, le nombre de sémaphores peut dynamiquement atteindre zéro thread lorsque toutes les autorisations disponibles ont été acquises par les threads. Cet état indique que le nombre maximum d'accès simultanés autorisés a été atteint.
Si vous le souhaitiez, vous pourriez définir le nombre initial et maximal de threads, en commençant le compte initial du sémaphore à zéro, puis en utilisant une tâche d'initialisation distincte qui augmente le compte du sémaphore lorsque la ressource est prête, permettant ainsi au nombre de threads choisi de progresser. Lorsque le compteur du sémaphore est à zéro, les threads attendront lorsqu'ils essaieront d'entrer dans le sémaphore, cela est appelé "attente bloquante".
Vous pourriez suivre le compte précédent du sémaphore pour ajuster le comportement du sémaphore en fonction du compte précédent. Vous pouvez ensuite manipuler le sémaphore en conséquence (par exemple, en le libérant ou en attendant). Au fur et à mesure que les threads se libèrent, le nombre de sémaphores diminue.
Sortie de la console
Cas d'utilisation courants pour SemaphoreSlim
Voici quelques cas d'utilisation courants de SemaphoreSlim :
Limitation de l'accès aux bases de données ou aux systèmes de fichiers : Cela évite de surcharger ces ressources avec trop de requêtes simultanées.
Gestion des pools de threads : Cela peut être utilisé pour contrôler le nombre de threads exécutant une opération particulière, améliorant ainsi la stabilité et les performances.
Utilisation de SemaphoreSlim avec IronPdf pour une Concurrence Sécurisée
Mise en place d'IronPDF dans un environnement multithreads
Pour commencer à utiliser IronPDF dans un environnement multithread, commencez par installer le package NuGet IronPDF. Vous pouvez le faire en naviguant vers Outils > Gestionnaire de package NuGet > Gestionnaire de package NuGet pour Solution et en recherchant IronPDF :
Ou, alternativement, exécutez la commande suivante dans la console du gestionnaire de packages :
Install-Package IronPdf
Pour commencer à utiliser IronPDF dans votre code, assurez-vous d'avoir placé l'instruction using IronPdf en haut de votre fichier de code. Pour un guide plus détaillé sur la configuration d'IronPDF dans votre environnement, consultez sa page d'initiation.
Contrôler l'accès à la génération de PDF avec SemaphoreSlim
En utilisant SemaphoreSlim, vous pouvez contrôler efficacement l'accès aux tâches de génération de PDF. Cela permet de s'assurer que votre application ne tente pas de générer trop de PDF simultanément, ce qui pourrait avoir un impact sur les performances ou provoquer des défaillances.
L'exemple de code suivant démontre l'utilisation de base de SemaphoreSlim avec 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
$vbLabelText $csharpLabel
Dans cet exemple, nous avons d'abord initialisé SemaphoreSlim et défini le nombre initial et maximal de SemaphoreSlim à "2", ce qui le limite à deux générations simultanées de PDF. Nous avons ensuite créé un tableau de tâches qui est utilisé pour contrôler le nombre de tâches que le programme doit effectuer, après quoi nous utilisons une boucle for pour créer dynamiquement des PDF en fonction du nombre de tâches dans le tableau de tâches.
La méthode WaitAsync() est ensuite utilisée pour entrer dans le sémaphore, et Release() est utilisé dans le bloc finally pour s'assurer que le sémaphore est toujours libéré même si une exception se produit. Les journaux de sortie de la console indiquent quand chaque tâche commence, finit et libère le sémaphore, ce qui vous permet de suivre le comportement de la concurrence.
Console de sortie
Fichiers PDF de sortie
Assurer la sécurité des threads dans les tâches de manipulation des PDF
La sécurité des threads est cruciale lorsque plusieurs threads interagissent avec des ressources partagées. Dans la manipulation des PDF, SemaphoreSlim garantit que seul un nombre défini de threads peut modifier les PDF simultanément, évitant ainsi les conditions de course et garantissant la cohérence. Dans le code suivant, nous simulons un scénario dans lequel nous ajoutons un filigrane à plusieurs PDF tout en veillant à ce qu'une seule opération se produise à la fois.
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
$vbLabelText $csharpLabel
En définissant le compteur de sémaphore à 1 en utilisant private static SemaphoreSlim _semaphore = new SemaphoreSlim(1);, nous nous assurons qu'une seule tâche peut manipuler des PDF à la fois.
Sortie de la console
Optimiser les performances avec SemaphoreSlim et IronPdf
Gestion des opérations à forte intensité de ressources
IronPDF excelle dans le traitement de tâches gourmandes en ressources, telles que la conversion de fichiers HTML volumineux en PDF, et excelle dans l'exécution de ces tâches dans un environnement asynchrone. L'utilisation de SemaphoreSlim pour gérer ces opérations garantit que votre application reste réactive sans perdre en performance, même en cas de forte charge.
L'exemple de code suivant illustre un scénario dans lequel nous devons limiter le nombre de conversions simultanées de gros fichiers HTML en fichiers PDF afin d'éviter de surcharger les ressources du système.
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
$vbLabelText $csharpLabel
Lorsqu'il s'agit de tâches gourmandes en ressources, comme la conversion de fichiers HTML volumineux en PDF, SemaphoreSlim peut aider à équilibrer la charge et à optimiser l'utilisation des ressources. En fixant une limite de 2 opérations simultanées, nous évitons que le système ne soit submergé par des tâches de génération de PDF gourmandes en ressources. Cette approche permet de mieux répartir la charge de travail et d'améliorer les performances et la stabilité de l'application dans son ensemble.
Image de sortie : Fichiers générés avec cette méthode
Éviter les blocages dans la gestion de la concurence
Des blocages peuvent se produire si les sémaphores ne sont pas libérés correctement. Une bonne pratique à garder à l'esprit est l'utilisation de blocs try-finally pour s'assurer que les sémaphores sont libérés même si une exception se produit, évitant ainsi les blocages et assurant le bon fonctionnement de votre application. Parmi les meilleures pratiques à retenir pour éviter les deadlocks figurent toujours la libération du sémaphore dans le bloc finally, et l'évitement d'utiliser des appels bloquants comme Wait() et Result dans votre code asynchrone.
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
$vbLabelText $csharpLabel
En utilisant un bloc try-catch-finally, nous avons assuré que l'objet SemaphoreSlim est toujours libéré, même si une exception est lancée, empêchant ainsi les blocages. En enregistrant les erreurs et en gérant correctement les libérations de sémaphores, nous pouvons maintenir le programme stable et éviter tout comportement inattendu.
Comme vous pouvez le voir dans l'image de sortie ci-dessous, j'ai simulé une erreur en essayant de faire en sorte que le programme charge un fichier HTML qui n'existe pas, mais même avec cette erreur, le programme imprime le message d'erreur qui m'indique ce qui n'a pas fonctionné et procède ensuite à la libération du sémaphore à l'aide du bloc finally.
Avantages de l'utilisation d'IronPDF pour le traitement simultané des PDF
Traitement efficace et fiable des PDF
IronPDF est conçu pour gérer efficacement les tâches de traitement PDF simultanées, offrant des performances et une fiabilité supérieures à celles de nombreuses autres bibliothèques PDF. Son architecture robuste lui permet de s'adapter aux besoins de votre application, ce qui en fait un outil idéal pour les environnements à forte demande. Lorsqu'on la compare à d'autres bibliothèques PDF sur la base des critères de performance, de facilité d'utilisation et de robustesse, IronPDF s'avère être un concurrent de taille. Pour le démontrer, j'ai comparé IronPdf à plusieurs autres bibliothèques PDF populaires telles que iTextSharp, PDFsharp, DinkToPdf et EvoPDF :
Performance
IronPDF :
Vitesse de rendu : IronPDF est reconnu pour ses capacités de rendu rapides et efficaces, notamment lors de la conversion de HTML en PDF. Elle utilise le rendu basé sur Chrome, qui offre une grande fidélité au contenu HTML d'origine, y compris l'exécution CSS et JavaScript.
Gestion des ressources : IronPDF est optimisé pour gérer des PDFs volumineux et complexes avec une utilisation réduite de la mémoire par rapport à d'autres bibliothèques, le rendant adapté aux applications à fort volume.
Opérations Asynchrones : Prend en charge la génération asynchrone de PDF, permettant une meilleure performance dans les applications web où la réactivité est cruciale.
iTextSharp :
Vitesse de rendu : iTextSharp offre de bonnes performances pour les PDF riches en texte, mais peut considérablement ralentir avec des mises en page complexes ou des images.
Gestion des ressources : L'utilisation de la mémoire peut être plus élevée avec iTextSharp, en particulier lors du traitement de documents volumineux ou de manipulations complexes, ce qui peut entraîner des goulets d'étranglement de performance dans certains cas.
PDFsharp :
Vitesse de rendu : PDFsharp est généralement plus lent comparé à IronPDF lors du traitement de mises en page complexes ou lors de la conversion depuis HTML, car il ne dispose pas d'un moteur de rendu HTML natif.
Gestion des ressources : Il est moins optimisé pour l'utilisation de la mémoire et peut rencontrer des difficultés avec les fichiers volumineux ou les documents contenant de nombreuses images.
DinkToPdf :
Vitesse de rendu : DinkToPdf utilise le moteur wkhtmltopdf, qui est efficace pour les conversions de base de HTML en PDF mais peut rencontrer des difficultés avec un contenu plus complexe ou dynamique.
Gestion des ressources : Elle nécessite souvent une mémoire et une puissance de traitement significatives, et manque de support natif pour les opérations asynchrones, ce qui limite ses performances dans des scénarios de haute charge.
EvoPDF :
Vitesse de rendu : EvoPDF propose également un rendu basé sur Chrome comme IronPDF, offrant de bonnes performances, en particulier pour les conversions de HTML en PDF.
Gestion des ressources : Il est bien optimisé mais peut encore consommer plus de ressources par rapport à IronPDF dans certains scénarios en raison d'optimisations moins agressives.
2. Facilité d'utilisation
IronPDF :
Conception de l'API : IronPDF offre une API moderne et intuitive qui est facile à utiliser pour les développeurs de tous niveaux de compétence. La bibliothèque est conçue pour fonctionner de manière transparente avec les applications .NET, ce qui en fait un excellent choix pour les développeurs C#.
Documentation et support : Une documentation complète, un grand nombre d'exemples de code et un excellent support client facilitent le démarrage et la résolution rapide des problèmes.
Installation et intégration : Facilement installé via NuGet, il s'intègre sans problème dans les projets .NET existants, nécessitant une configuration minimale.
iTextSharp :
Conception de l'API : iTextSharp a une courbe d'apprentissage abrupte, avec une API plus complexe qui peut être intimidante pour les débutants. Sa flexibilité se fait au détriment de la simplicité.
Documentation et support : Bien que bien documentées, les nombreuses options de configuration peuvent rendre plus difficile la recherche d'exemples simples pour les tâches courantes.
Installation et intégration : Disponible via NuGet, mais nécessite une compréhension approfondie de l'API pour une intégration efficace.
PDFsharp :
Conception de l'API : PDFsharp est conçu pour être simple pour les tâches PDF de base, mais il manque de fonctionnalités avancées par défaut, ce qui peut limiter son utilisation dans des scénarios plus complexes.
Documentation et support : Une documentation de base est disponible, mais elle est moins exhaustive et manque d'exemples détaillés pour une utilisation avancée par rapport à IronPDF.
Installation et intégration : Facile à installer via NuGet mais offre des fonctionnalités limitées de conversion HTML en PDF.
DinkToPdf :
Conception API : L'API de DinkToPdf est relativement simple mais moins aboutie comparée à IronPDF. Elle vise principalement la conversion de HTML en PDF et offre moins de fonctionnalités pour la manipulation directe de PDF.
Documentation et support : La documentation est limitée, et le support communautaire n'est pas aussi robuste que celui d'autres bibliothèques, ce qui rend le dépannage plus difficile.
Installation et Intégration : Peut être plus complexe à installer, nécessitant des dépendances supplémentaires comme wkhtmltopdf, ce qui peut compliquer la configuration.
EvoPDF :
Conception de l'API : EvoPDF offre une API simple similaire à IronPDF, axée principalement sur la conversion de HTML en PDF avec facilité d'utilisation à l'esprit.
Documentation et support : Bien documenté avec de bonnes options de support, mais pas aussi étendu dans les exemples communautaires que IronPDF.
Installation et Intégration : Facile à intégrer dans des projets .NET avec des packages NuGet disponibles.
3. Robustesse
IronPDF :
Ensemble de fonctionnalités : IronPDF est très robuste et prend en charge une large gamme de fonctionnalités, y compris la conversion HTML en PDF, l'édition de PDF, l'extraction de texte, le chiffrement, les annotations et les signatures numériques.
Gestion des erreurs : Offre une gestion des erreurs robuste et une gestion des exceptions, ce qui le rend fiable pour les environnements de production.
Compatibilité : Entièrement compatible avec .NET Core, .NET 5+ et les versions héritées de .NET Framework, ce qui le rend polyvalent pour différents types de projets.
iTextSharp :
Ensemble de fonctionnalités : iTextSharp est extrêmement robuste avec un ensemble de fonctionnalités complet qui prend en charge presque toutes les tâches PDF, y compris les manipulations complexes et la gestion de formulaires.
Gestion des erreurs : Bonne gestion des erreurs mais peut être complexe à gérer en raison des complexités de la bibliothèque.
Compatibilité : Bien adapté à une large gamme d'environnements, y compris .NET Framework et .NET Core.
PDFsharp :
Ensemble de fonctionnalités : Fonctions de base de création et de manipulation de PDF. Il manque certaines fonctionnalités avancées telles que la conversion de HTML en PDF et l'édition de documents plus sophistiqués.
Gestion des erreurs : Gestion des erreurs de base ; est moins fiable dans des scénarios complexes par rapport à des bibliothèques plus robustes comme IronPDF.
Compatibilité : Compatible avec .NET Framework et .NET Core, mais avec des fonctionnalités avancées limitées.
DinkToPdf :
Ensemble de fonctionnalités : Principalement axé sur la conversion de HTML en PDF. Limité en termes de manipulation directe des PDF et dépourvu de fonctions avancées telles que les annotations et la gestion des formulaires.
Gestion des erreurs : Gestion des erreurs de base ; le logiciel a tendance à se bloquer ou à se bloquer sur des fichiers HTML complexes ou des fichiers volumineux.
Compatibilité : Fonctionne avec .NET Core et .NET Framework mais nécessite des dépendances externes, ce qui peut introduire des problèmes de compatibilité.
EvoPDF :
Ensemble de fonctionnalités : Offre un ensemble de fonctionnalités solide similaire à IronPDF, y compris des conversions HTML en PDF avancées et certaines capacités de manipulation de documents.
Gestion des erreurs : Gestion des erreurs robuste et performance fiable dans les environnements de production.
Compatibilité : Entièrement compatible avec .NET Core, .NET Framework, et les versions plus récentes de .NET, ce qui le rend polyvalent et fiable.
Résumé
Performance : IronPDF et EvoPDF sont en tête en termes de performance grâce à leurs moteurs de rendu basés sur Chrome, tandis qu'iTextSharp et PDFsharp peuvent être moins performants dans le traitement de documents complexes.
Facilité d'utilisation : IronPDF excelle avec son API intuitive et sa documentation exhaustive, le rendant accessible à tous les niveaux de développeurs. iTextSharp offre de la puissance au détriment de la simplicité, tandis que DinkToPdf et PDFsharp sont plus faciles à utiliser mais moins riches en fonctionnalités.
Robustesse : IronPDF et iTextSharp offrent les ensembles de fonctionnalités les plus robustes, avec IronPDF proposant une intégration plus simple et des fonctionnalités modernes comme la prise en charge asynchrone, tandis que iTextSharp couvre des cas d'utilisation plus spécialisés avec une courbe d'apprentissage plus abrupte.
Prise en charge complète de la programmation asynchrone
IronPDF s'intègre parfaitement aux modèles de programmation async, complétant les mécanismes de contrôle de la concurrence tels que SemaphoreSlim. Cela permet aux développeurs de créer des applications réactives et performantes avec un minimum d'efforts.
IronPDF propose également une documentation complète et des ressources d'assistance qui aident les développeurs à comprendre et à mettre en œuvre des pratiques efficaces de traitement des erreurs. Ce support complet est précieux pour dépanner et optimiser les opérations PDF dans les projets .NET.
IronPDF propose :
Documentation complète : Documentation exhaustive et conviviale couvrant toutes les fonctionnalités.
Support 24/5 : Le support d'ingénieur actif est disponible.
Tutoriels vidéo : Des guides vidéo étape par étape sont disponibles sur YouTube.
Forum Communautaire : Communauté engagée pour un support supplémentaire.
Référence API PDF : Propose des références API pour que vous puissiez tirer le meilleur parti de ce que nos outils ont à offrir.
Pour plus d'informations, consultez la vaste documentation d'IronPDF.
Conclusion
L'utilisation de SemaphoreSlim pour la gestion de la concurrence dans les applications .NET est cruciale, en particulier lorsqu'il s'agit de tâches gourmandes en ressources comme le traitement des PDF. En intégrant SemaphoreSlim à IronPDF, les développeurs peuvent obtenir un contrôle des concurrences sûr, efficace et fiable, garantissant que leurs applications restent réactives et respectueuses des performances.
Découvrez comment IronPdf peut rationaliser vos flux de travail de traitement des PDF. Essayez-le vous-même avec sa version d'essai gratuite, qui commence à partir de seulement $749 si vous souhaitez continuer à utiliser cet outil puissant dans vos projets.
Chaknith travaille sur IronXL et IronBarcode. Il possède une expertise approfondie en C# et .NET, aidant à améliorer le logiciel et à soutenir les clients. Ses idées issues des interactions avec les utilisateurs contribuent à de meilleurs produits, une documentation améliorée et une expérience globale enrichie.
< PRÉCÉDENT C# Init Keyword (Comment ça marche pour les développeurs)
SUIVANT > C# try catch finally (Comment ça marche pour les développeurs)
Des millions d'ingénieurs dans le monde entier lui font confiance
Réservez une démo en direct gratuite
Réservez une démonstration personnelle de 30 minutes.
Pas de contrat, pas de détails de carte, pas d'engagements.
Voici ce à quoi vous pouvez vous attendre :
Une démonstration en direct de notre produit et de ses principales fonctionnalités
Obtenez des recommandations de fonctionnalités spécifiques au projet
Toutes vos questions trouvent réponse pour vous assurer de disposer de toutes les informations dont vous avez besoin. (Aucun engagement de votre part.)
CHOISIR L'HEURE
VOS INFORMATIONS
Réservez votre démo en direct gratuite
Fiable par plus de 2 millions d'ingénieurs dans le monde entier