跳至頁尾內容
.NET幫助

C# Concurrentdictionary(它是如何運作的開發者用途)

在使用C#的多執行緒應用程式時,維護資料完整性至關重要,特別是當您使用像IronPDF這樣的程式庫隨時生成PDF文件時。 ConcurrentDictionary<tkey, tvalue>類別提供了一個執行緒安全的集合,以有效管理鍵和值對,即使多個執行緒同時執行插入、更新或查找等操作。

在這份指南中,我們將探討ConcurrentDictionary的運作原理、它如何整合IronPDF進行平行PDF處理,以及每位.NET開發人員需要了解的鍵型別、執行緒安全性和常見陷阱,例如處理已存在的鍵或確保資料一致性。

What is a ConcurrentDictionary in C#?

ConcurrentDictionary<tkey, tvalue>類別是System.Collections.Concurrent命名空間的一部分,是一個通用集合,設計用於高效能的執行緒安全操作。 與普通字典不同,它允許多個執行緒在不鎖定整個結構的情況下安全地存取和修改集合。

一個新的ConcurrentDictionary<string, string>實例可能會是這樣的:

var dictionary = new ConcurrentDictionary<string, string>();
var dictionary = new ConcurrentDictionary<string, string>();
Dim dictionary = New ConcurrentDictionary(Of String, String)()
$vbLabelText   $csharpLabel

您可以根據具體的使用案例定義您自己的TKey和TValue型別,例如快取渲染的PDF文件路徑或追蹤並行的PDF生成任務。

為什麼要將ConcurrentDictionary與IronPDF一起使用?

假想您正在構建一個程式,使用IronPDF為成千上萬的使用者生成個性化的發票。 如果每個執行緒需要渲染文件並儲存其結果,普通字典可能會引入競爭條件或在鍵已存在時拋出例外。

使用ConcurrentDictionary可以確保:

  • 各執行緒之間的資料一致性
  • 高效的讀寫
  • 預防未知的程式碼錯誤
  • 當多個執行緒操作不同鍵時,零鎖定的開銷

常用方法及其與IronPDF的使用

讓我們分解使用IronPDF渲染場景的關鍵方法。

GetOrAdd方法:檢索或新增新鍵

此方法檢查指定的鍵是否存在。 如果不存在,則新增新值。

var filePath = pdfCache.GetOrAdd(userId, id => GeneratePdfForUser(id));
var filePath = pdfCache.GetOrAdd(userId, id => GeneratePdfForUser(id));
Dim filePath = pdfCache.GetOrAdd(userId, Function(id) GeneratePdfForUser(id))
$vbLabelText   $csharpLabel
  • 確保執行緒安全
  • 避免重複渲染
  • 返回與給定鍵相應的值

AddOrUpdate方法:平穩地處理現有值

此方法允許您在鍵存在時更新值,或者新增新的鍵值對。

pdfCache.AddOrUpdate(userId,
    id => GeneratePdfForUser(id),
    (id, existingValue) => UpdatePdfForUser(id, existingValue));
pdfCache.AddOrUpdate(userId,
    id => GeneratePdfForUser(id),
    (id, existingValue) => UpdatePdfForUser(id, existingValue));
pdfCache.AddOrUpdate(userId, Function(id) GeneratePdfForUser(id), Function(id, existingValue) UpdatePdfForUser(id, existingValue))
$vbLabelText   $csharpLabel
  • 管理現有鍵的邏輯
  • 確保在併發環境下存取的成員是安全的

TryAdd方法:如果鍵不存在則新增

此方法嘗試新增值並返回一個指示成功的布林值。

bool added = pdfCache.TryAdd(userId, pdfBytes);
if (!added)
{
    Console.WriteLine("PDF already cached.");
}
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
$vbLabelText   $csharpLabel
  • 非常適合避免衝突
  • 如果插入成功,則方法返回true

使用案例表:ConcurrentDictionary方法

C# Concurrentdictionary(它如何為開發人員運作):圖1 - 使用案例表

優化性能

ConcurrentDictionary支持通過構造函式調整設置:

int concurrencyLevel = 4;
int initialCapacity = 100;
var dictionary = new ConcurrentDictionary<string, byte[]>(concurrencyLevel, initialCapacity);
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)
$vbLabelText   $csharpLabel
  • concurrencyLevel:預期的執行緒數(預設=預設併發級別)
  • initialCapacity:預期的元素數量(預設初始容量)

正確設置這些參數可以提高吞吐量,並減少多個執行緒之間的爭奪。

防止鍵衝突和預設值的問題

當鍵不存在時,TryGetValue等操作可以返回該型別的預設值:

if (!pdfCache.TryGetValue(userId, out var pdf))
{
    pdf = GeneratePdfForUser(userId); // Second call
}
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 If
$vbLabelText   $csharpLabel

這保護您的程式碼免受未知程式碼或空引用的影響。 在假設存在之前,請始終檢查特定值。

實際範例:執行緒安全的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; }
}
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 Class
$vbLabelText   $csharpLabel

已保存文件

C# Concurrentdictionary(它如何為開發人員運作):圖2 - 按指定保存的範例文件

範例輸出

C# Concurrentdictionary(它如何為開發人員運作):圖3 - 範例PDF文件

程式碼分解

此範例展示瞭如何結合ConcurrentDictionary<TKey, TValue>與IronPDF以執行緒安全的方式生成PDF。 這非常適合多個執行緒同時處理和快取PDF文件的應用程式。

為什麼要使用ConcurrentDictionary?

  • 確保執行緒安全地存取鍵值對。
  • GetOrAdd()避免重複的PDF生成。
  • 無需手動鎖定——非常適合高併發。 工作原理

  • 一個使用者列表,每個使用者都有一個ID和HTML。
  • Parallel.ForEach產生執行緒以生成PDF。
  • 每個執行緒都使用GetOrAdd()來獲取或建立PDF。
  • PDF使用使用者的ID作為文件名保存。 總結

當以下情況時,此模式是理想選擇:

  • 您正在為眾多使用者同時生成PDF。
  • 您需要性能和執行緒安全。
  • 您希望在C#中保持清晰、可靠的併發性。

擴展方法和存取模式

雖然ConcurrentDictionary不提供所有LINQ功能,但您仍然可以使用擴展方法來查詢值:

var completedKeys = pdfReports.Keys.Where(k => k.StartsWith("done-")).ToList();
var completedKeys = pdfReports.Keys.Where(k => k.StartsWith("done-")).ToList();
Dim completedKeys = pdfReports.Keys.Where(Function(k) k.StartsWith("done-")).ToList()
$vbLabelText   $csharpLabel

但是,請避免依賴迭代期間複製的元素,因為詞典可能會改變。 如果需要,可以使用.ToList().ToArray()來處理快照。

結論:執行緒安全符合PDF自動化

ConcurrentDictionary<TKey, TValue>非常適合多個執行緒需要同時讀取/寫入鍵值對的場景——使其成為多執行緒應用程式中IronPDF的完美搭檔。

無論您是在快取渲染的PDF、追踪作業狀態,還是防止冗余操作,使用這個執行緒安全的集合可確保您的邏輯隨著性能和可靠性進行擴展。

立即嘗試IronPDF

準備好構建具備完整執行緒安全的高性能PDF應用程式嗎? 下載IronPDF的免費試用 ,體驗無縫的PDF生成,結合C#的ConcurrentDictionary的功能。

常見問題

ConcurrentDictionary如何在多執行緒C#應用程式中提升效能?

ConcurrentDictionary透過允許多個執行緒同時執行插入、更新和查找等操作來提升多執行緒C#應用程式中的效能,而不需要外部鎖定,從而保持資料完整性。

將ConcurrentDictionary與IronPDF結合使用的意義為何?

使用ConcurrentDictionary與IronPDF具有重要意義,因其允許在平行PDF處理中進行執行緒安全的資料管理,確保PDF生成在多執行緒環境中高效且不發生資料衝突。

ConcurrentDictionary可以用於管理C#中的並發PDF生成嗎?

是的,ConcurrentDictionary可以用於在C#中管理並發PDF生成,確保操作在多個執行緒間安全處理,提高PDF生成過程的效能和可靠性。

為什麼在C#中生成PDF時執行緒安全很重要?

在C#中生成PDF時,執行緒安全很重要以避免資料損壞,確保一致的輸出,特別是在動態建立和修改PDF文件涉及多個執行緒時。

使用ConcurrentDictionary可以同時執行哪些操作?

使用ConcurrentDictionary可以同時執行插入、更新、查找和刪除等操作,這使其非常適合需要執行緒安全資料管理的高效能應用程式。

IronPDF如何處理並發操作?

IronPDF透過使用ConcurrentDictionary等執行緒安全集合來處理並發操作,這允許在多個執行緒間高效地進行PDF處理和資料管理,而不影響資料完整性。

在使用ConcurrentDictionary時需要實施外部鎖定嗎?

不,使用ConcurrentDictionary不需要實施外部鎖定,因為它設計為本身具備執行緒安全性,並發操作由內部管理。

開發者如何在C#應用程式中優化PDF處理?

開發者可以透過將ConcurrentDictionary等執行緒安全集合與IronPDF等程式庫整合,啟用高效且可靠的平行PDF文件處理,來優化C#應用程式中的PDF處理。

Jacob Mellor,首席技術官 @ Team Iron
首席技術官

Jacob Mellor是Iron Software的首席技術官,一位在C# PDF技術上開創先河的遠見工程師。作為Iron Software核心程式碼庫的原開發者,他從創立以來就一直在塑造公司的產品架構,與首席執行官Cameron Rimington一起將公司轉變為服務於NASA、特斯拉和全球政府公司的50多名人員的公司。

Jacob擁有曼徹斯特大學的土木工程一等榮譽學士學位(BEng),於1998-2001年之間獲得。在1999年於倫敦創辦他的第一家軟體公司並於2005年建立了他的第一批.NET元組件後,他專注於解決Microsoft生態系統中的複雜問題。

他的旗艦IronPDF和Iron Suite .NET程式庫在全球獲得了超過3000萬次NuGet安裝依據,他的基礎程式碼基繼續支援著世界各地開發者使用的工具。擁有25年的商業經驗和41年的程式設計專業知識,他仍專注於推動企業級C#、Java和Python PDF技術的創新,同時指導下一代技術領導者。

Iron 支援團隊

我們線上24小時,每週5天。
聊天
電子郵件
給我打電話