
C# Concurrentdictionary (Jak to działa dla deweloperów)
Podczas pracy z aplikacjami wielowątkowymi w C#, utrzymanie integralności danych jest kluczowe, zwłaszcza kiedy generujesz dokumenty PDF na bieżąco, używając biblioteki takiej jak IronPDF. Klasa ConcurrentDictionary<tkey, tvalue> zapewnia typową dla wątków kolekcję do efektywnego zarządzania parami klucz-wartość, nawet gdy wiele wątków jednocześnie wykonuje operacje takie jak wstawianie, aktualizacja lub wyszukiwanie.
W tym przewodniku przeanalizujemy, jak działa ConcurrentDictionary, jak można go zintegrować z IronPDF do równoległego przetwarzania PDF, oraz co każdy programista .NET powinien wiedzieć o typach kluczy, bezpieczeństwie wątków i częstych pułapkach, takich jak obsługa istniejącego klucza lub zapewnianie spójności danych.
What is a ConcurrentDictionary in C#?
Klasa ConcurrentDictionary<tkey, tvalue>, będąca częścią przestrzeni nazw System.Collections.Concurrent, to ogólna kolekcja zaprojektowana do operacji o wysokiej wydajności i wątkoodporności. W przeciwieństwie do zwykłego słownika, pozwala na bezpieczny dostęp i modyfikację kolekcji przez wiele wątków bez blokowania całej struktury.
Nowa instancja ConcurrentDictionary<string, string> może wyglądać tak:
var dictionary = new ConcurrentDictionary<string, string>();Dim dictionary = New ConcurrentDictionary(Of String, String)()Możesz zdefiniować własne typy TKey i TValue w oparciu o konkretne zastosowanie, takie jak buforowanie ścieżek do wyrenderowanych plików PDF lub śledzenie równoległych zadań generowania PDF.
Dlaczego warto używać ConcurrentDictionary z IronPDF?
Wyobraź sobie, że budujesz program, który generuje personalizowane faktury za pomocą IronPDF dla tysięcy użytkowników. Jeśli każdy wątek musi wyrenderować dokument i przechowywać wynik, zwykły słownik wprowadziłby warunki wyścigu lub generował wyjątki, jeśli klucz już istnieje.
Używanie ConcurrentDictionary zapewnia:
- Spójność danych w wątkach
- Efektywne operacje odczytu i zapisu
- Zapobieganie nieznanym błędom w kodzie
- Brak narzutów blokowania, gdy wiele wątków działa na różnych kluczach
Popularne metody i ich użycie z IronPDF
Przeanalizujmy kluczowe metody przy użyciu scenariuszy renderowania IronPDF.
Metoda GetOrAdd: Pobierz lub dodaj nowy klucz
Ta metoda sprawdza, czy istnieje określony klucz. Jeśli nie, dodaje nową wartość.
var filePath = pdfCache.GetOrAdd(userId, id => GeneratePdfForUser(id));Dim filePath = pdfCache.GetOrAdd(userId, Function(id) GeneratePdfForUser(id))- Zapewnia bezpieczeństwo wątków
- Unika podwójnego renderowania
- Zwraca powiązaną wartość dla danego klucza
Metoda AddOrUpdate: Zarządzanie istniejącą wartością w sposób przyjazny
Ta metoda pozwala zaktualizować wartość, jeśli klucz istnieje, lub dodać nową parę klucz-wartość.
pdfCache.AddOrUpdate(userId,
id => GeneratePdfForUser(id),
(id, existingValue) => UpdatePdfForUser(id, existingValue));pdfCache.AddOrUpdate(userId, Function(id) GeneratePdfForUser(id), Function(id, existingValue) UpdatePdfForUser(id, existingValue))- Zarządza logiką dla istniejącego klucza
- Zapewnia, że członkowie są dostępni w warunkach współbieżności
Metoda TryAdd: Dodaj, jeśli klucz nie istnieje
Ta metoda próbuje dodać wartość i zwraca wartość logiczną wskazującą na sukces.
bool added = pdfCache.TryAdd(userId, pdfBytes);
if (!added)
{
Console.WriteLine("PDF already cached.");
}Dim added As Boolean = pdfCache.TryAdd(userId, pdfBytes)
If Not added Then
Console.WriteLine("PDF already cached.")
End If- Idealna do unikania konfliktów
- Metoda zwraca wartość true, jeśli wstawienie się powiedzie
Tabela przypadków użycia: Metody ConcurrentDictionary

Optymalizacja wydajności
ConcurrentDictionary wspiera dostrajanie przez konstruktor:
int concurrencyLevel = 4;
int initialCapacity = 100;
var dictionary = new ConcurrentDictionary<string, byte[]>(concurrencyLevel, initialCapacity);Dim concurrencyLevel As Integer = 4
Dim initialCapacity As Integer = 100
Dim dictionary = New ConcurrentDictionary(Of String, Byte())(concurrencyLevel, initialCapacity)- poziom współbieżności: spodziewana liczba wątków (domyślnie = domyślny poziom współbieżności)
- początkowa pojemność: spodziewana liczba elementów (domyślna początkowa pojemność)
Poprawne ustawienie tych parametrów zwiększa przepustowość i zmniejsza rywalizację w wątkach.
Zapobieganie problemom z konfliktami kluczy i domyślnymi ustawieniami
Gdy klucz nie istnieje, operacje takie jak TryGetValue mogą zwracać wartość domyślną dla typu:
if (!pdfCache.TryGetValue(userId, out var pdf))
{
pdf = GeneratePdfForUser(userId); // Second call
}Dim pdf As var
If Not pdfCache.TryGetValue(userId, pdf) Then
pdf = GeneratePdfForUser(userId) ' Second call
End IfTo zabezpiecza twój kod przed nieznanym kodem lub odwołaniami null. Zawsze sprawdzaj dla konkretnej wartości, zanim założysz obecność.
Praktyczny przykład: Wątko-odporny generator raportów IronPDF
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using IronPdf;
public class Program
{
static ConcurrentDictionary<string, byte[]> pdfReports =
new ConcurrentDictionary<string, byte[]>();
static void Main(string[] args)
{
// Simulated user list with HTML content
var users = new List<User>
{
new User { Id = "user1", HtmlContent = "<h1>Report for User 1</h1>" },
new User { Id = "user2", HtmlContent = "<h1>Report for User 2</h1>" },
new User { Id = "user3", HtmlContent = "<h1>Report for User 3</h1>" }
};
// Generate PDFs concurrently
var renderer = new ChromePdfRenderer();
Parallel.ForEach(users, user =>
{
var pdf = pdfReports.GetOrAdd(user.Id, id =>
{
var pdfDoc = renderer.RenderHtmlAsPdf(user.HtmlContent);
return pdfDoc.BinaryData;
});
SaveToFile(pdf, $"{user.Id}.pdf");
});
Console.WriteLine("PDF generation complete.");
}
// Utility method to write PDF binary data to file
static void SaveToFile(byte[] pdfBytes, string filePath)
{
File.WriteAllBytes(filePath, pdfBytes);
Console.WriteLine($"Saved: {filePath}");
}
}
// Simple user class with ID and HTML content
public class User
{
public string Id { get; set; }
public string HtmlContent { get; set; }
}Imports System
Imports System.Collections.Concurrent
Imports System.Collections.Generic
Imports System.IO
Imports System.Threading.Tasks
Imports IronPdf
Public Class Program
Private Shared pdfReports As New ConcurrentDictionary(Of String, Byte())()
Shared Sub Main(ByVal args() As String)
' Simulated user list with HTML content
Dim users = New List(Of User) From {
New User With {
.Id = "user1",
.HtmlContent = "<h1>Report for User 1</h1>"
},
New User With {
.Id = "user2",
.HtmlContent = "<h1>Report for User 2</h1>"
},
New User With {
.Id = "user3",
.HtmlContent = "<h1>Report for User 3</h1>"
}
}
' Generate PDFs concurrently
Dim renderer = New ChromePdfRenderer()
Parallel.ForEach(users, Sub(user)
Dim pdf = pdfReports.GetOrAdd(user.Id, Function(id)
Dim pdfDoc = renderer.RenderHtmlAsPdf(user.HtmlContent)
Return pdfDoc.BinaryData
End Function)
SaveToFile(pdf, $"{user.Id}.pdf")
End Sub)
Console.WriteLine("PDF generation complete.")
End Sub
' Utility method to write PDF binary data to file
Private Shared Sub SaveToFile(ByVal pdfBytes() As Byte, ByVal filePath As String)
File.WriteAllBytes(filePath, pdfBytes)
Console.WriteLine($"Saved: {filePath}")
End Sub
End Class
' Simple user class with ID and HTML content
Public Class User
Public Property Id() As String
Public Property HtmlContent() As String
End ClassZapisane pliki

Przykładowy wynik

Analiza kodu
Ten przykład pokazuje, jak połączyć ConcurrentDictionary<TKey, TValue> z IronPDF, aby generować PDF-y w sposób bezpieczny dla wątku. Jest idealny dla aplikacji, w których wiele wątków jednocześnie przetwarza i buforuje pliki PDF.
Dlaczego ConcurrentDictionary?
-
Zapewnia bezpieczny dla wątku dostęp do par klucz-wartość.
-
GetOrAdd()unika podwójnego generowania PDF. -
Nie potrzeba ręcznych blokad—idealne dla wysokiej współbieżności. Jak to działa
-
Lista użytkowników, z których każdy posiada ID i HTML.
-
Parallel.ForEach tworzy wątki do generowania PDF.
-
Każdy wątek używa
GetOrAdd(), aby pobrać lub stworzyć PDF. -
PDF jest zapisywany z użyciem ID użytkownika jako nazwy pliku. Podsumowanie
Ten wzór jest idealny, gdy:
- Generujesz PDF-y dla wielu użytkowników jednocześnie.
- Potrzebujesz wydajności i bezpieczeństwa wątków.
- Chcesz czystości i niezawodności współbieżności w C#.
Metody rozszerzeń i wzorce dostępu
Chociaż ConcurrentDictionary nie udostępnia wszystkich funkcji LINQ, możesz nadal używać metod rozszerzeń do zapytań o wartości:
var completedKeys = pdfReports.Keys.Where(k => k.StartsWith("done-")).ToList();Dim completedKeys = pdfReports.Keys.Where(Function(k) k.StartsWith("done-")).ToList()Jednak unikaj polegania na elementach skopiowanych podczas iteracji, ponieważ słownik może się zmienić. Użyj .ToList() lub .ToArray(), aby korzystać ze zrzutu, jeśli to potrzebne.
Podsumowanie: Bezpieczeństwo wątków spotyka automatyzację PDF
ConcurrentDictionary<TKey, TValue> jest idealny do scenariuszy, w których wiele wątków musi jednocześnie odczytywać i zapisywać pary klucz-wartość—dzięki czemu stanowi doskonałe uzupełnienie dla IronPDF w aplikacjach wielowątkowych.
Niezależnie od tego czy buforujesz renderowane pliki PDF, śledzisz status zadania, czy zapobiegasz powtarzającym się operacjom, używanie tej bezpiecznej względem wątków kolekcji zapewnia skalowanie logiki z wydajnością i niezawodnością.
Wypróbuj IronPDF już dziś
Gotowy do budowy wysokowydajnych aplikacji PDF z pełnym bezpieczeństwem wątków? Pobierz bezpłatną wersję próbną IronPDF i doświadcz płynnego generowania PDF połączonego z mocą ConcurrentDictionary w C#.

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ącą ponad 50 osób, obsługującą NASA, Teslę i światowe agencje rządowe.
Powiązane artykuły


