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 sólo permiten que un mismo 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 segura para 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 asegura que cada envío es 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 recommendedBooks = new ConcurrentDictionary();
ConcurrentDictionary recommendedBooks = new ConcurrentDictionary();
Dim recommendedBooks As New ConcurrentDictionary()
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 seguras como TryRemove
y TryUpdate
. Estos métodos aseguran que sólo un hilo puede 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 RemoveAt
.
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 ofrece colecciones seguras diseñ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#.
IronPDF es una popular biblioteca de C# que permite generar documentos PDF a partir de HTML sin esfuerzo.
using IronPdf;
class Program
{
static void Main(string [] args)
{
var renderer = new ChromePdfRenderer();
// 1. Convertir cadena HTML a 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. Convertir archivo HTML a PDF
var htmlFilePath = "path_to_your_html_file.html"; // Especifique la ruta a su archivo HTML
var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");
// 3. Convertir URL a PDF
var url = "http://ironpdf.com"; // Especificar la URL
var pdfFromUrl = renderer.RenderUrlAsPdf(url);
pdfFromUrl.SaveAs("URLToPDF.pdf");
}
}
using IronPdf;
class Program
{
static void Main(string [] args)
{
var renderer = new ChromePdfRenderer();
// 1. Convertir cadena HTML a 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. Convertir archivo HTML a PDF
var htmlFilePath = "path_to_your_html_file.html"; // Especifique la ruta a su archivo HTML
var pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath);
pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf");
// 3. Convertir URL a PDF
var url = "http://ironpdf.com"; // Especificar la 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. Convertir cadena HTML a 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. Convertir archivo HTML a PDF
Dim htmlFilePath = "path_to_your_html_file.html" ' Especifique la ruta a su archivo HTML
Dim pdfFromHtmlFile = renderer.RenderHtmlFileAsPdf(htmlFilePath)
pdfFromHtmlFile.SaveAs("HTMLFileToPDF.pdf")
' 3. Convertir URL a PDF
Dim url = "http://ironpdf.com" ' Especificar la 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;
// Crear un diccionario concurrente para guardar los datos procesados
ConcurrentDictionary processedData = new ConcurrentDictionary();
// Defina su lista de datos (sustitúyala por su fuente de datos real)
List dataList = GetDataList();
// Procese sus datos simultáneamente y almacene los resultados en el diccionario
Parallel.ForEach(dataList, (dataItem) =>
{
string processedResult = ProcessDataItem(dataItem);
processedData.TryAdd(dataItem.Id, processedResult);
});
// Generar un informe PDF con los datos procesados
var renderer = new ChromePdfRenderer();
var pdfDocument = renderer.RenderHtmlAsPdf(BuildHtmlReport(processedData));
pdfDocument.SaveAs("C:\\processed_data_report.pdf");
// Método para recuperar la lista de datos (sustitúyalo por la lógica de su fuente de datos real)
List GetDataList()
{
List dataList = new List()
{
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;
}
// Método para procesar cada dato y devolver el resultado (sustitúyalo por su lógica real de procesamiento de datos)
string ProcessDataItem(DataItem dataItem)
{
// Simulación de tratamiento de datos con retraso
Task.Delay(100).Wait();
return $"Processed: {dataItem.Name}";
}
// Método para crear el informe HTML utilizando los datos procesados (sustitúyalo por su propia lógica de elaboración de informes)
string BuildHtmlReport(ConcurrentDictionary processedData)
{
string html = "Processed Data Report";
foreach (var kvp in processedData)
{
html += $"Item {kvp.Key}: {kvp.Value}";
}
html += "";
return html;
}
// Clase de marcador de posición para el elemento de datos (sustitúyala por la clase real del elemento de datos)
public class DataItem
{
public int Id { get; set; }
public string Name { get; set; }
// Añada otras propiedades según sea necesario
}
using IronPdf;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
// Crear un diccionario concurrente para guardar los datos procesados
ConcurrentDictionary processedData = new ConcurrentDictionary();
// Defina su lista de datos (sustitúyala por su fuente de datos real)
List dataList = GetDataList();
// Procese sus datos simultáneamente y almacene los resultados en el diccionario
Parallel.ForEach(dataList, (dataItem) =>
{
string processedResult = ProcessDataItem(dataItem);
processedData.TryAdd(dataItem.Id, processedResult);
});
// Generar un informe PDF con los datos procesados
var renderer = new ChromePdfRenderer();
var pdfDocument = renderer.RenderHtmlAsPdf(BuildHtmlReport(processedData));
pdfDocument.SaveAs("C:\\processed_data_report.pdf");
// Método para recuperar la lista de datos (sustitúyalo por la lógica de su fuente de datos real)
List GetDataList()
{
List dataList = new List()
{
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;
}
// Método para procesar cada dato y devolver el resultado (sustitúyalo por su lógica real de procesamiento de datos)
string ProcessDataItem(DataItem dataItem)
{
// Simulación de tratamiento de datos con retraso
Task.Delay(100).Wait();
return $"Processed: {dataItem.Name}";
}
// Método para crear el informe HTML utilizando los datos procesados (sustitúyalo por su propia lógica de elaboración de informes)
string BuildHtmlReport(ConcurrentDictionary processedData)
{
string html = "Processed Data Report";
foreach (var kvp in processedData)
{
html += $"Item {kvp.Key}: {kvp.Value}";
}
html += "";
return html;
}
// Clase de marcador de posición para el elemento de datos (sustitúyala por la clase real del elemento de datos)
public class DataItem
{
public int Id { get; set; }
public string Name { get; set; }
// Añada otras propiedades según sea necesario
}
Imports IronPdf
Imports System.Collections.Concurrent
Imports System.Collections.Generic
Imports System.Threading.Tasks
' Crear un diccionario concurrente para guardar los datos procesados
Private processedData As New ConcurrentDictionary()
' Defina su lista de datos (sustitúyala por su fuente de datos real)
Private dataList As List = GetDataList()
' Procese sus datos simultáneamente y almacene los resultados en el diccionario
Parallel.ForEach(dataList, Sub(dataItem)
Dim processedResult As String = ProcessDataItem(dataItem)
processedData.TryAdd(dataItem.Id, processedResult)
End Sub)
' Generar un informe PDF con los datos procesados
Dim renderer = New ChromePdfRenderer()
Dim pdfDocument = renderer.RenderHtmlAsPdf(BuildHtmlReport(processedData))
pdfDocument.SaveAs("C:\processed_data_report.pdf")
' Método para recuperar la lista de datos (sustitúyalo por la lógica de su fuente de datos real)
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'List GetDataList()
'{
' List dataList = New List() { 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;
'}
' Método para procesar cada dato y devolver el resultado (sustitúyalo por su lógica real de procesamiento de datos)
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'string ProcessDataItem(DataItem dataItem)
'{
' ' Simulación de tratamiento de datos con retraso
' Task.Delay(100).Wait();
' Return string.Format("Processed: {0}", dataItem.Name);
'}
' Método para crear el informe HTML utilizando los datos procesados (sustitúyalo por su propia lógica de elaboración de informes)
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
'string BuildHtmlReport(ConcurrentDictionary processedData)
'{
' string html = "Processed Data Report";
' foreach (var kvp in processedData)
' {
' html += string.Format("Item {0}: {1}", kvp.Key, kvp.Value);
' }
' html += "";
' Return html;
'}
' Clase de marcador de posición para el elemento de datos (sustitúyala por la clase real del elemento de datos)
'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;
' }
' ' Añada otras propiedades según sea necesario
'}
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 un prueba gratuita que le permite explorar sus capacidades, y opciones de licencia a partir de $749.
9 productos API .NET para sus documentos de oficina