Pruebas en un entorno real
Pruebe en producción sin marcas de agua.
Funciona donde lo necesites.
Si alguna vez has tenido varios subprocesos disputándose el acceso a un recurso compartido, sabrás que la implementación segura de subprocesos no es un juego. Pero no te preocupes! C# le ofrece colecciones concurrentes: un potente conjunto de clases de colección genéricas y seguras para subprocesos que garantizan la seguridad de los subprocesos con estilo y elegancia.
Empecemos imaginando un animado cruce urbano sin semáforos. Puedes imaginarte el caos! Esto es similar a lo que ocurre cuando varios subprocesos acceden simultáneamente a un recurso compartido sin un sistema adecuado. Afortunadamente, en C#, tenemos semáforos para nuestros hilos - se llaman colecciones concurrentes. Son clases de colección que permiten que sólo un hilo acceda a un recurso a la vez. Esta seguridad es crucial cuando se trabaja con varios subprocesos.
En C#, el espacio de nombres System.Collections.Concurrent
tiene una variedad de clases de colecciones concurrentes, como ConcurrentDictionary
, ConcurrentQueue
, ConcurrentStack
, y ConcurrentBag
. Estas clases de colecciones desordenadas proporcionan una versión a prueba de hilos de sus homólogas no concurrentes. Lo que diferencia a las colecciones concurrentes es que son colecciones concurrentes desordenadas, lo que significa que los elementos no tienen un orden específico. Por ejemplo, con una lista concurrente, no se sabe exactamente dónde se inserta un elemento. La atención se centra en garantizar la seguridad de las roscas, no en mantener un orden.
Tomemos un ejemplo de la vida real. Piense en un puesto de envío de contraseñas en un sitio web. Con una recopilación concurrente, varios usuarios pueden enviar sus contraseñas simultáneamente. Cada acción de "envío" es como un hilo, y la colección concurrente garantiza que cada envío sea seguro para el hilo, procesado de forma segura y eficaz.
Ahora, vamos a explorar la clase de colección ConcurrentDictionary
con un ejemplo de la vida real. Imagine una librería en línea con una función de recomendación. Cada clic del usuario añade un libro a su lista personal de recomendaciones, representada por un diccionario. Como varios usuarios navegan y hacen clic en los libros al mismo tiempo, tenemos varios hilos accediendo simultáneamente al diccionario.
Un ConcurrentDictionary
en C# tendría este aspecto:
ConcurrentDictionary<string, string> recommendedBooks = new ConcurrentDictionary<string, string>();
ConcurrentDictionary<string, string> recommendedBooks = new ConcurrentDictionary<string, string>();
Dim recommendedBooks As New ConcurrentDictionary(Of String, String)()
Para añadir un libro a toda la colección de recomendaciones de un usuario, podríamos utilizar el método 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
En este escenario, la clase de colección ConcurrentDictionary
garantiza que cada clic(o "hilo) se trata de forma individual, por lo que no se mezclan las recomendaciones de dos usuarios. Maneja toda la seguridad de los hilos, por lo que no tienes que preocuparte por las carreras de datos y otros problemas de concurrencia relacionados con múltiples hilos.
Además de TryAdd
, las colecciones concurrentes en C# proporcionan una variedad de otras operaciones a prueba de hilos como TryRemove
y TryUpdate
. Estos métodos garantizan que sólo un hilo pueda realizar una operación a la vez. Así, por ejemplo, si quisiéramos eliminar un libro de las recomendaciones de un usuario en el ejemplo anterior, podríamos utilizar el método 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
El método TryRemove
intentará eliminar el valor de la clave proporcionada(en este caso, un usuario) y ponerlo en la variable removedBook
.
Ahora, digamos que quieres copiar tu colección concurrente a un array. Las colecciones concurrentes proporcionan un método CopyTo
para este propósito exacto:
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
Aquí, el método CopyTo
copia todos los libros(valores) del diccionario concurrente Libros recomendados
al Array de libros
.
C# también ofrececolecciones segurasdiseñados para garantizar un acceso seguro a los recursos compartidos en entornos multihilo. Estas colecciones, como ConcurrentBag
, ConcurrentQueue
y ConcurrentStack
, ofrecen implementaciones a prueba de hilos en las que varios hilos pueden acceder a la colección y modificarla simultáneamente sin causar conflictos ni corrupción de datos.
Garantizan la coherencia y la integridad mediante la gestión interna de la sincronización, por lo que son ideales para situaciones en las que una colección desordenada es suficiente y la seguridad de los subprocesos es de suma importancia en sus aplicaciones C#.
Más información sobre IronPDF es una popular biblioteca de C# que permitegenerar documentos PDF a partir de HTML sin esfuerzo.
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
Aunque al principio puede no parecer directamente relacionado con las listas concurrentes, IronPDF puede complementar sus operaciones de recolección concurrente proporcionando una forma sencilla de crear informes PDF, registros o cualquier otro documento que capture los resultados de su procesamiento concurrente.
Considere el escenario en el que tiene una aplicación multihilo que realiza un procesamiento intensivo de datos. A medida que los hilos trabajan su magia en los datos, es posible que desee capturar los resultados y generar un informe en PDF para su posterior análisis o mantenimiento de registros. Aquí es donde IronPDF entra en juego.
Utilizar IronPDF es tan sencillo como añadir la biblioteca a su proyecto y utilizar su práctica API. He aquí un ejemplo de cómo puede integrar IronPDF en sus operaciones de recogida simultánea:
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
'}
Este es el resultado del código:
En conclusión, comprender y utilizar las colecciones concurrentes de C#, como las listas concurrentes, puede mejorar enormemente su capacidad para manejar escenarios multihilo y garantizar la seguridad de los hilos en sus aplicaciones. Las colecciones concurrentes permiten gestionar eficazmente los recursos compartidos, evitando las carreras de datos y las colisiones entre subprocesos.
La integración de bibliotecas externas como IronPDF puede aumentar aún más la funcionalidad de las colecciones concurrentes al permitir la generación de informes o documentos PDF visualmente atractivos. IronPDF ofrece unprueba gratuita de su biblioteca para la conversión de HTML a PDFque le permite explorar sus capacidades, y opciones de licencia a partir de $749.
9 productos API .NET para sus documentos de oficina