跳過到頁腳內容
.NET幫助

C# Concurrentdictionary(開發者工作方式)

在 C# 中,處理多執行緒應用程式時,保持數據完整性至關重要,尤其是當您使用像 IronPDF 這樣的庫即時生成 PDF 文檔時。 The ConcurrentDictionary<tkey, tvalue> class provides a thread-safe collection to manage key and value pairs efficiently, even when multiple threads concurrently perform operations like insertions, updates, or lookups.

在本指南中,我們將探索 ConcurrentDictionary 的工作原理,它如何與 IronPDF 集成進行並行 PDF 處理,以及每個 .NET 開發者需要了解的鍵類型、線程安全性以及如何處理現有鍵或確保數據一致性等常見陷阱。

C# 中的 ConcurrentDictionary 是什麼?

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 等库集成来优化 C# 应用程序中的 PDF 处理,实现 PDF 文档的高效可靠并行处理。

Curtis Chau
技術作家

Curtis Chau 擁有卡爾頓大學計算機科學學士學位,專注於前端開發,擅長於 Node.js、TypeScript、JavaScript 和 React。Curtis 熱衷於創建直觀且美觀的用戶界面,喜歡使用現代框架並打造結構良好、視覺吸引人的手冊。

除了開發之外,Curtis 對物聯網 (IoT) 有著濃厚的興趣,探索將硬體和軟體結合的創新方式。在閒暇時間,他喜愛遊戲並構建 Discord 機器人,結合科技與創意的樂趣。