Test dans un environnement réel
Test en production sans filigrane.
Fonctionne partout où vous en avez besoin.
Si vous avez déjà eu plusieurs threads se bousculant pour accéder à une ressource partagée, vous savez que l'implémentation de la sécurité des threads n'est pas un jeu. Ne vous inquiétez pas! C# vous couvre avec les collections concurrentes - une suite puissante de classes de collection génériques et sûres pour les threads qui garantissent la sécurité des threads avec style et élégance.
Imaginons tout d'abord un carrefour urbain animé sans feux de signalisation. Vous pouvez imaginer le chaos! Ce phénomène est similaire à celui qui se produit lorsque plusieurs threads accèdent simultanément à une ressource partagée sans qu'un système adéquat soit en place. Heureusement, en C#, nous disposons de feux de signalisation pour nos threads - ce sont les collections concurrentes. Il s'agit de classes de collection qui permettent à un seul thread d'accéder à une ressource à la fois. Cette sécurité des threads est cruciale lorsque l'on travaille avec plusieurs threads.
En C#, l'espace de noms System.Collections.Concurrent
contient une variété de classes de collections concurrentes, comme ConcurrentDictionary
, ConcurrentQueue
, ConcurrentStack
, et ConcurrentBag
. Ces classes de collections non ordonnées fournissent une version thread-safe de leurs homologues non simultanés. Les collections concurrentes se distinguent par le fait qu'elles sont non ordonnées, c'est-à-dire que les éléments n'ont pas d'ordre spécifique. Par exemple, dans le cas d'une liste concurrente, vous ne savez pas exactement où un élément est inséré. L'accent est mis sur la sécurité du fil, et non sur le maintien de l'ordre.
Prenons un exemple concret. Pensez à un poste de soumission de mot de passe sur un site web. Avec une collection concurrente, plusieurs utilisateurs peuvent soumettre leurs mots de passe simultanément. Chaque action de "soumission" est comme un fil conducteur, et la collection concurrente garantit que chaque soumission est à l'abri des fils conducteurs, traitée en toute sécurité et de manière efficace.
Explorons maintenant la classe de collection ConcurrentDictionary
à l'aide d'un exemple concret. Imaginez une librairie en ligne dotée d'une fonction de recommandation. Chaque clic de l'utilisateur ajoute un livre à sa liste de recommandations personnelles, représentée par un dictionnaire. Comme plusieurs utilisateurs naviguent et cliquent sur des livres en même temps, plusieurs fils d'exécution accèdent simultanément au dictionnaire.
Un ConcurrentDictionary
en C# ressemblerait à ceci :
ConcurrentDictionary<string, string> recommendedBooks = new ConcurrentDictionary<string, string>();
ConcurrentDictionary<string, string> recommendedBooks = new ConcurrentDictionary<string, string>();
Dim recommendedBooks As New ConcurrentDictionary(Of String, String)()
Pour ajouter un livre à l'ensemble des recommandations d'un utilisateur, nous pourrions utiliser la méthode Insert
:
public void Insert(string user, string book)
{
recommendedBooks.TryAdd(user, book);
}
public void Insert(string user, string book)
{
recommendedBooks.TryAdd(user, book);
}
Public Sub Insert(ByVal user As String, ByVal book As String)
recommendedBooks.TryAdd(user, book)
End Sub
Dans ce scénario, la classe de collection ConcurrentDictionary
garantit que chaque clic(ou "thread" (fil)) est traitée individuellement, de sorte que les recommandations de deux utilisateurs ne soient pas mélangées. Il gère toute la sécurité des threads, de sorte que vous n'avez pas à vous soucier des courses de données et autres problèmes de concurrence liés à des threads multiples.
Outre TryAdd
, les collections concurrentes en C# fournissent une variété d'autres opérations sûres pour les threads comme TryRemove
et TryUpdate
. Ces méthodes garantissent qu'un seul thread peut effectuer une opération à la fois. Ainsi, par exemple, si nous voulions supprimer un livre des recommandations d'un utilisateur dans l'exemple précédent, nous pourrions utiliser la méthode TryRemove
:
public void RemoveAt(string user)
{
string removedBook;
recommendedBooks.TryRemove(user, out removedBook);
}
public void RemoveAt(string user)
{
string removedBook;
recommendedBooks.TryRemove(user, out removedBook);
}
Public Sub RemoveAt(ByVal user As String)
Dim removedBook As String = Nothing
recommendedBooks.TryRemove(user, removedBook)
End Sub
La méthode TryRemove
tentera de supprimer la valeur de la clé fournie(dans ce cas, un utilisateur) et le place dans la variable removedBook
.
Imaginons maintenant que vous souhaitiez copier votre collection concurrente dans un tableau. Les collections concurrentes fournissent une méthode CopyTo
dans ce but précis :
public void CopyTo()
{
string[] bookArray = new string[recommendedBooks.Count];
recommendedBooks.Values.CopyTo(bookArray, 0);
}
public void CopyTo()
{
string[] bookArray = new string[recommendedBooks.Count];
recommendedBooks.Values.CopyTo(bookArray, 0);
}
Public Sub CopyTo()
Dim bookArray(recommendedBooks.Count - 1) As String
recommendedBooks.Values.CopyTo(bookArray, 0)
End Sub
Ici, la méthode CopyTo
copie tous les livres(valeurs) du dictionnaire concurrent recommendedBooks
dans le bookArray
.
C# fournit égalementcollections sûres pour les threadsqui sont conçus pour garantir un accès sûr aux ressources partagées dans les environnements multithreads. Ces collections, telles que ConcurrentBag
, ConcurrentQueue
et ConcurrentStack
, offrent des implémentations sûres pour les threads où plusieurs threads peuvent accéder à la collection et la modifier simultanément sans provoquer de conflits ou de corruption de données.
Ils garantissent la cohérence et l'intégrité en gérant la synchronisation en interne, ce qui les rend idéaux pour les scénarios où une collection non ordonnée est suffisante et où la sécurité des threads est de la plus haute importance dans vos applications C#.
En savoir plus sur IronPDF est une bibliothèque C# populaire qui vous permet degénérer des documents PDF à partir de HTML sans effort.
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
// 1. Convert HTML String to PDF
var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");
// 2. Convert HTML File to PDF
var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");
// 3. Convert URL to PDF
var url = "http://ironpdf.com"; // Specify the URL
var pdfFromUrl = renderer.RenderUrlAsPdf(url);
pdfFromUrl.SaveAs("URLToPDF.pdf");
}
}
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
// 1. Convert HTML String to PDF
var htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>";
var pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent);
pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf");
// 2. Convert HTML File to PDF
var htmlFilePath = "path_to_your_html_file.html"; // Specify the path to your HTML file
var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");
// 3. Convert URL to PDF
var url = "http://ironpdf.com"; // Specify the URL
var pdfFromUrl = renderer.RenderUrlAsPdf(url);
pdfFromUrl.SaveAs("URLToPDF.pdf");
}
}
Imports IronPdf
Friend Class Program
Shared Sub Main(ByVal args() As String)
Dim renderer = New ChromePdfRenderer()
' 1. Convert HTML String to PDF
Dim htmlContent = "<h1>Hello, IronPDF!</h1><p>This is a PDF from an HTML string.</p>"
Dim pdfFromHtmlString = renderer.RenderHtmlAsPdf(htmlContent)
pdfFromHtmlString.SaveAs("HTMLStringToPDF.pdf")
' 2. Convert HTML File to PDF
Dim htmlFilePath = "path_to_your_html_file.html" ' Specify the path to your HTML file
Dim pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath)
pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf")
' 3. Convert URL to PDF
Dim url = "http://ironpdf.com" ' Specify the URL
Dim pdfFromUrl = renderer.RenderUrlAsPdf(url)
pdfFromUrl.SaveAs("URLToPDF.pdf")
End Sub
End Class
Bien qu'il ne semble pas directement lié aux listes concurrentes à première vue, IronPDF peut compléter vos opérations de collecte simultanée en fournissant un moyen facile de créer des rapports PDF, des journaux ou tout autre document qui capture les résultats de votre traitement simultané.
Prenons le cas d'une application multithread qui effectue un traitement intensif des données. Au fur et à mesure que les fils opèrent leur magie sur les données, vous voudrez peut-être capturer les résultats et générer un rapport PDF en vue d'une analyse plus approfondie ou de la tenue d'archives. C'est là qu'IronPDF entre en jeu.
Pour utiliser IronPDF, il suffit d'ajouter la bibliothèque à votre projet et d'utiliser son API pratique. Voici un exemple de la façon dont vous pouvez intégrer IronPDF à vos opérations de collecte simultanée :
using IronPdf;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
// Create a concurrent dictionary to hold your processed data
ConcurrentDictionary<int, string> processedData = new ConcurrentDictionary<int, string>();
// Define your data list (replace with your actual data source)
List<DataItem> dataList = GetDataList();
// Process your data concurrently and store the results in the dictionary
Parallel.ForEach(dataList, (dataItem) =>
{
string processedResult = ProcessDataItem(dataItem);
processedData.TryAdd(dataItem.Id, processedResult);
});
// Generate a PDF report with the processed data
var renderer = new ChromePdfRenderer();
var pdfDocument = renderer.RenderHtmlAsPdf(BuildHtmlReport(processedData));
pdfDocument.SaveAs("C:\\processed_data_report.pdf");
// Method to retrieve the data list (replace with your actual data source logic)
List<DataItem> GetDataList()
{
List<DataItem> dataList = new List<DataItem>()
{
new DataItem { Id = 1, Name = "Item 1" },
new DataItem { Id = 2, Name = "Item 2" },
new DataItem { Id = 3, Name = "Item 3" },
new DataItem { Id = 4, Name = "Item 4" }
};
return dataList;
}
// Method to process each data item and return the result (replace with your actual data processing logic)
string ProcessDataItem(DataItem dataItem)
{
// Simulating data processing with a delay
Task.Delay(100).Wait();
return $"Processed: {dataItem.Name}";
}
// Method to build the HTML report using the processed data (replace with your actual reporting logic)
string BuildHtmlReport(ConcurrentDictionary<int, string> processedData)
{
string html = "<h1>Processed Data Report</h1><ul>";
foreach (var kvp in processedData)
{
html += $"<li>Item {kvp.Key}: {kvp.Value}</li>";
}
html += "</ul>";
return html;
}
// Placeholder class for your data item (replace with your actual data item class)
public class DataItem
{
public int Id { get; set; }
public string Name { get; set; }
// Add other properties as needed
}
using IronPdf;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
// Create a concurrent dictionary to hold your processed data
ConcurrentDictionary<int, string> processedData = new ConcurrentDictionary<int, string>();
// Define your data list (replace with your actual data source)
List<DataItem> dataList = GetDataList();
// Process your data concurrently and store the results in the dictionary
Parallel.ForEach(dataList, (dataItem) =>
{
string processedResult = ProcessDataItem(dataItem);
processedData.TryAdd(dataItem.Id, processedResult);
});
// Generate a PDF report with the processed data
var renderer = new ChromePdfRenderer();
var pdfDocument = renderer.RenderHtmlAsPdf(BuildHtmlReport(processedData));
pdfDocument.SaveAs("C:\\processed_data_report.pdf");
// Method to retrieve the data list (replace with your actual data source logic)
List<DataItem> GetDataList()
{
List<DataItem> dataList = new List<DataItem>()
{
new DataItem { Id = 1, Name = "Item 1" },
new DataItem { Id = 2, Name = "Item 2" },
new DataItem { Id = 3, Name = "Item 3" },
new DataItem { Id = 4, Name = "Item 4" }
};
return dataList;
}
// Method to process each data item and return the result (replace with your actual data processing logic)
string ProcessDataItem(DataItem dataItem)
{
// Simulating data processing with a delay
Task.Delay(100).Wait();
return $"Processed: {dataItem.Name}";
}
// Method to build the HTML report using the processed data (replace with your actual reporting logic)
string BuildHtmlReport(ConcurrentDictionary<int, string> processedData)
{
string html = "<h1>Processed Data Report</h1><ul>";
foreach (var kvp in processedData)
{
html += $"<li>Item {kvp.Key}: {kvp.Value}</li>";
}
html += "</ul>";
return html;
}
// Placeholder class for your data item (replace with your actual data item class)
public class DataItem
{
public int Id { get; set; }
public string Name { get; set; }
// Add other properties as needed
}
Imports IronPdf
Imports System.Collections.Concurrent
Imports System.Collections.Generic
Imports System.Threading.Tasks
' Create a concurrent dictionary to hold your processed data
Private processedData As New ConcurrentDictionary(Of Integer, String)()
' Define your data list (replace with your actual data source)
Private dataList As List(Of DataItem) = GetDataList()
' Process your data concurrently and store the results in the dictionary
Parallel.ForEach(dataList, Sub(dataItem)
Dim processedResult As String = ProcessDataItem(dataItem)
processedData.TryAdd(dataItem.Id, processedResult)
End Sub)
' Generate a PDF report with the processed data
Dim renderer = New ChromePdfRenderer()
Dim pdfDocument = renderer.RenderHtmlAsPdf(BuildHtmlReport(processedData))
pdfDocument.SaveAs("C:\processed_data_report.pdf")
' Method to retrieve the data list (replace with your actual data source logic)
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'List(Of DataItem) GetDataList()
'{
' List<DataItem> dataList = New List<DataItem>() { New DataItem { Id = 1, Name = "Item 1" }, New DataItem { Id = 2, Name = "Item 2" }, New DataItem { Id = 3, Name = "Item 3" }, New DataItem { Id = 4, Name = "Item 4" } };
' Return dataList;
'}
' Method to process each data item and return the result (replace with your actual data processing logic)
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'string ProcessDataItem(DataItem dataItem)
'{
' ' Simulating data processing with a delay
' Task.Delay(100).Wait();
' Return string.Format("Processed: {0}", dataItem.Name);
'}
' Method to build the HTML report using the processed data (replace with your actual reporting logic)
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'string BuildHtmlReport(ConcurrentDictionary(Of int, string) processedData)
'{
' string html = "<h1>Processed Data Report</h1><ul>";
' foreach (var kvp in processedData)
' {
' html += string.Format("<li>Item {0}: {1}</li>", kvp.Key, kvp.Value);
' }
' html += "</ul>";
' Return html;
'}
' Placeholder class for your data item (replace with your actual data item class)
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'public class DataItem
'{
' public int Id
' {
' get;
' set;
' }
' public string Name
' {
' get;
' set;
' }
' ' Add other properties as needed
'}
Voici le résultat du code :
En conclusion, la compréhension et l'utilisation des collections concurrentes C#, telles que les listes concurrentes, peuvent grandement améliorer votre capacité à gérer des scénarios multithreading et à garantir la sécurité des threads dans vos applications. Les collections concurrentes permettent de gérer efficacement les ressources partagées, en évitant les conflits de données et les collisions entre les threads.
L'intégration de bibliothèques externes telles qu'IronPDF peut encore accroître la fonctionnalité des collections concurrentes en permettant la génération de rapports ou de documents PDF visuellement attrayants. IronPDF offre un service deessai gratuit de sa bibliothèque pour la conversion de HTML en PDFvous permettant d'explorer ses capacités, et les options de licence à partir de $749.
9 produits de l'API .NET pour vos documents de bureau