Lista współbieżna w języku C# (jak działa dla programistów)
Jeśli kiedykolwiek miales wiele wątków rywalizujacych o dostep do wspoldzielonego zasobu, wiesz, ze implementacja bezpieczeństwa wątków to nie jest zabawa. Ale nie martw sie! C# oferuje zbior wspolbieznych kolekcji - potężny zestaw rodzajowych klas kolekcji, ktore zapewniają bezpieczeństwo wątków z wdziękiem i stylem.
Thread Safety and Concurrent Collections in C
Zacznijmy od wyobrazania sobie ruchliwego skrzyzowania w miescie bez światel drogowych. Możesz wyobrazic sobie chaos! Jest to podobne do sytuacji, w której wiele wątków jednocześnie uzyskuje dostęp do wspólnego zasobu bez odpowiedniego systemu. Na szczęście, w C# mamy światla drogowe dla naszych wątków - nazywaja sie one wspolbiezne kolekcje. Sa to klasy kolekcji, ktore pozwalają tylko jednemu wątkówi na raz uzyskać dostep do zasobu. To bezpieczeństwo wątków jest kluczowe podczas pracy z wieloma watkami.
Exploring Concurrent Thread Safe Collections in C
W C# przestrzeń nazw System.Collections.Concurrent zawiera różnorodne klasy kolekcji współbieżnych, takie jak ConcurrentDictionary, ConcurrentQueue, ConcurrentStack i ConcurrentBag. Te nieuporzadkowane klasy kolekcji dostarczaj wersje bezpieczne dla wątków swoich nie-wspolbieznych odpowiednikow. Czym różnią sie wspolbiezne kolekcje, to fakt, ze sa to kolekcje wspolbiezne nieuporzadkowane, co oznacza, ze elementy nie maja konkretnej kolejnosci. Na przykład, z lista wspolbiezna, nie wiesz dokladnie, gdzie dany element zostaje wstawiony. Skupienie jest na zapewnieniu bezpieczeństwa wątków, a nie na utrzymaniu kolejnosci.
Wezmy przykład zycia codziennego. Pomyśl o przesylaniu hasla na stronie internetowej. Z kolekcja wspolbiezna, wielu użytkowników może jednoczesnie przesylac swoje hasla. Kazda akcja 'przeslij' jest jak wątek, a kolekcja wspolbiezna zapewnia, ze kazde przesylanie jest bezpieczne dla wątków, przetwarzane bezpiecznie i skutecznie.
ConcurrentDictionary: Przyklad z zycia wzięty
Teraz przeanalizujmy klasę kolekcji ConcurrentDictionary na przykładzie z codziennego życia. Wyobraz sobie ksiegarnie online z funkcja rekomendacji. Kazde klikniecie użytkownika dodaje ksiazke do jego osobistej listy rekomendacji, reprezentowanej przez slownik. Poniewaz wielu użytkowników przegląda i klika ksiazki w tym samym czasie, mamy wiele wątków jednoczesnie uzyskujacych dostep do slownika.
Obiekt ConcurrentDictionary w C# wyglądałby mniej więcej tak:
using System.Collections.Concurrent;
ConcurrentDictionary<string, string> recommendedBooks = new ConcurrentDictionary<string, string>();
using System.Collections.Concurrent;
ConcurrentDictionary<string, string> recommendedBooks = new ConcurrentDictionary<string, string>();
Imports System.Collections.Concurrent
Private recommendedBooks As New ConcurrentDictionary(Of String, String)()
Aby dodać książkę do całej kolekcji rekomendacji użytkownika, moglibyśmy użyć metody TryAdd:
public void Insert(string user, string book)
{
// Try to add the book to the user's recommendations
recommendedBooks.TryAdd(user, book);
}
public void Insert(string user, string book)
{
// Try to add the book to the user's recommendations
recommendedBooks.TryAdd(user, book);
}
Public Sub Insert(ByVal user As String, ByVal book As String)
' Try to add the book to the user's recommendations
recommendedBooks.TryAdd(user, book)
End Sub
W tym scenariuszu klasa kolekcji ConcurrentDictionary zapewnia, że każdy klik (lub 'wątek') jest traktowany indywidualnie, dzięki czemu rekomendacje różnych użytkowników nie są mieszane. Obsługuje ona wszystkie kwestie bezpieczeństwa wątków, więc nie musisz martwić się o konkurencję danych i inne problemy z równoczesnością związane z wieloma wątkami.
Implementacja operacji bezpiecznych dla wątków
Poza TryAdd, współbieżne kolekcje w C# oferują różne inne operacje bezpieczne dla wątków, takie jak TryRemove i TryUpdate. Te metody zapewniają, że tylko jeden wątek może wykonać operację w danym momencie. Na przykład, jeśli chcielibyśmy usunąć książkę z rekomendacji użytkownika we wcześniejszym przykładzie, moglibyśmy użyć metody TryRemove:
public void RemoveAt(string user)
{
// Attempt to remove the book for the specified user
string removedBook;
recommendedBooks.TryRemove(user, out removedBook);
}
public void RemoveAt(string user)
{
// Attempt to remove the book for the specified user
string removedBook;
recommendedBooks.TryRemove(user, out removedBook);
}
Public Sub RemoveAt(ByVal user As String)
' Attempt to remove the book for the specified user
Dim removedBook As String = Nothing
recommendedBooks.TryRemove(user, removedBook)
End Sub
Metoda TryRemove spróbuje usunąć wartość dla podanego klucza (w tym przypadku, użytkownika) i umieści ją w zmiennej removedBook.
Kopiowanie wspolbieznych kolekcji
Powiedzmy teraz, ze chcesz skopiowac swoja wspolbiezna kolekcje do tablicy. Kolekcje współbieżne zapewniają metodę CopyTo dokładnie do tego celu:
public void CopyTo()
{
// Create an array to hold the recommended books
string[] bookArray = new string[recommendedBooks.Count];
// Copy the values of the concurrent dictionary to the array
recommendedBooks.Values.CopyTo(bookArray, 0);
}
public void CopyTo()
{
// Create an array to hold the recommended books
string[] bookArray = new string[recommendedBooks.Count];
// Copy the values of the concurrent dictionary to the array
recommendedBooks.Values.CopyTo(bookArray, 0);
}
Public Sub CopyTo()
' Create an array to hold the recommended books
Dim bookArray(recommendedBooks.Count - 1) As String
' Copy the values of the concurrent dictionary to the array
recommendedBooks.Values.CopyTo(bookArray, 0)
End Sub
Tutaj metoda CopyTo kopiuje wszystkie książki (wartości) ze współbieżnego słownika recommendedBooks do bookArray.
Kolekcja bezpieczna dla wątków
C# dostarcza również kolekcje bezpieczne dla wątków, ktore sa zaprojektowane, aby zapewnic bezpieczny dostep do wspoldzielonych zasobów w środowiskach wielowątkówych. Te kolekcje, takie jak ConcurrentBag, ConcurrentQueue i ConcurrentStack, oferują implementacje bezpieczne dla wątków, w których wiele wątków może jednocześnie uzyskać dostęp do kolekcji i ją modyfikować bez powodowania konfliktów lub uszkodzenia danych.
Gwarantuja one spojnosc i integralnosc poprzez wewnetrzna synchronizacje, dzięki czemu sa idealne do scenariuszy, w ktorych wystarczy nieuporzadkowana kolekcja, a bezpieczeństwo wątków ma kluczowe znaczenie w aplikacjach C#.
Dowiedz sie więcej o IronPDF to popularna biblioteka C#, która pozwala łatwo generować dokumenty PDF z HTML.
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
Chociaż na pierwszy rzut oka może nie wydawac sie bezpośrednio związana ze wspolbiezna lista, IronPDF może uzupełniać operacje wspolbieznych kolekcji poprzez zapewnienie prostego sposobu tworzenia raportow PDF, dziennikow czy innych dokumentów ujmujacych wyniki przetwarzania wspolbieznego.
Rozwaz scenariusz, w ktorym masz aplikacje wielowątkówa wykonująca intensywne przetwarzanie danych. Podczas gdy wątki wykonują swoją magie na danych, możesz chciec uchwycic wyniki i wygenerować raport PDF do dalszej analizy czy dokumentacji. W tym miejscu do gry wkracza IronPDF.
Uzycie IronPDF jest proste jak dodanie biblioteki do projektu i skorzystanie z jej wygodnego API. Oto przykład, jak możesz zintegrowac IronPDF z operacjami wspolbieznych kolekcji:
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) =>
{
// Process each data item and add the result to the dictionary
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) =>
{
// Process each data item and add the result to the dictionary
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)
' Process each data item and add the result to the dictionary
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
'}
Oto wynik działania kodu:

Wnioski
Podsumowujac, zrozumienie i wykorzystanie wspolbieznych kolekcji w C#, takich jak wspolbiezne listy, może znacznie zwiększyć twoja zdolnosc do radzenia sobie z sytuacjami wielowątkówymi i zapewnienia bezpieczeństwa wątków w twoich aplikacjach. Dzięki wspolbieznych kolekcjom możesz skutecznie zarządzać wspoldzielonymi zasobami, zapobiegając wyscigom danych i kolizjom miedzy watkami.
Integracja zewnętrznych bibliotek takich jak IronPDF może dodatkowo wzbogacić funkcjonalność wspolbieznych kolekcji, umożliwiajac generowanie atrakcyjnych wizualnie raportow czy dokumentów PDF. IronPDF oferuje darmowy okres próbny swojej biblioteki do konwersji HTML na PDF, pozwalając na zbadanie jej możliwości, a opcje licencjonowania zaczynają się od $999.
Często Zadawane Pytania
Czym są współbieżne kolekcje w C#?
Współbieżne kolekcje w C# to zbiór bezpiecznych dla wątków, generycznych klas kolekcji, które zapewniają bezpieczeństwo wątków, gdy wiele wątków uzyskuje dostęp do współdzielonych zasobów.
Dlaczego bezpieczeństwo wątków jest ważne w C#?
Bezpieczeństwo wątków jest kluczowe w C# w celu zapobiegania chaosowi i uszkodzeniu danych, gdy wiele wątków jednocześnie uzyskuje dostęp do i modyfikuje współdzielone zasoby. Zapewnia, że operacje są wykonywane w kontrolowany sposób.
Jak mogę stworzyć listę bezpieczną dla wątków w C#?
Chociaż C# nie zapewnia bezpośrednio klasy List bezpiecznej dla wątków, można użyć innych współbieżnych kolekcji, takich jak `ConcurrentBag` lub `ConcurrentDictionary` do podobnych operacji bezpiecznych dla wątków.
Czym jest ConcurrentDictionary w C#?
`ConcurrentDictionary` w C# to klasa kolekcji bezpieczna dla wątków w przestrzeni nazw `System.Collections.Concurrent`. Pozwala wielu wątkom bezpiecznie dodawać, aktualizować i usuwać pary klucz-wartość jednocześnie.
Jak ConcurrentDictionary zapewnia bezpieczeństwo wątków?
`ConcurrentDictionary` zapewnia bezpieczeństwo wątków, obsługując synchronizację wewnętrznie, pozwalając tylko jednemu wątkowi na wykonywanie operacji, takich jak dodawanie czy usuwanie elementów naraz.
Jak można dodać element do ConcurrentDictionary?
Możesz dodać element do `ConcurrentDictionary` używając metody TryAdd, która próbuje dodać parę klucz-wartość tylko wtedy, gdy klucz jeszcze nie istnieje w słowniku.
Jaki jest cel metody CopyTo w współbieżnych kolekcjach?
Metoda `CopyTo` w współbieżnych kolekcjach jest używana do kopiowania elementów kolekcji do tablicy, co pozwala na przeniesienie danych z kolekcji do innego formatu przechowywania.
Czy IronPDF może być używany do generowania raportów PDF z przetworzonych danych?
Tak, IronPDF może być używany do generowania raportów PDF z danych przetworzonych przez aplikacje wielowątkowe, rejestrując wyniki współbieżnych operacji.
Jak użycie IronPDF zwiększa funkcjonalność współbieżnych operacji?
IronPDF zwiększa operacje współbieżne, umożliwiając tworzenie dokumentów PDF z przetworzonych danych, oferując sposób na dokumentówanie i udostępnianie wyników przetwarzania wielowątkowego.
Jaką rolę pełni IronPDF w aplikacjach wielowątkowych C#?
IronPDF pozwala deweloperom generować raporty PDF z danych przetworzonych równolegle, ułatwiając konsolidację i udostępnianie wyników operacji wielowątkowych.




