Przejdź do treści stopki
POMOC .NET

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)()
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
'}
$vbLabelText   $csharpLabel

Oto wynik działania kodu:

C# Concurrent List (Jak to działa dla deweloperów) Rysunek 1 - Wynik

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.

Jacob Mellor, Dyrektor Technologiczny @ Team Iron
Dyrektor ds. technologii

Jacob Mellor jest Chief Technology Officer w Iron Software i wizjonerskim inżynierem, pionierem technologii C# PDF. Jako pierwotny deweloper głównej bazy kodowej Iron Software, kształtuje architekturę produktów firmy od jej początku, przekształcając ją wspólnie z CEO Cameron Rimington w firmę liczą...

Czytaj więcej

Zespół wsparcia Iron

Jesteśmy online 24 godziny, 5 dni w tygodniu.
Czat
E-mail
Zadzwoń do mnie