フッターコンテンツにスキップ
.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生成タスクを追跡する場合です。

IronPDFでConcurrentDictionaryを使用する理由

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を返す

Use Case Table: ConcurrentDictionary Methods

C# Concurrentdictionary (How it Works for Developers): Figure 1 - Use case table

パフォーマンス向上の最適化

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 (How it Works for Developers): Figure 2 - Example files saved as specified

例の出力

C# Concurrentdictionary (How it Works for Developers): Figure 3 - Example PDF document

コードの内訳

この例は、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とC#のConcurrentDictionaryの力を組み合わせたシームレスなPDF生成を体験してください。

よくある質問

C#のマルチスレッドアプリケーションでConcurrentDictionaryがどのようにしてパフォーマンスを向上させるか?

ConcurrentDictionaryは外部ロックを必要とせずに、挿入、更新、検索といった操作を複数のスレッドで同時に行うことで、C#のマルチスレッドアプリケーションのパフォーマンスを向上させ、データ整合性を維持します。

IronPDFとConcurrentDictionaryを使用することの重要性は何ですか?

IronPDFでConcurrentDictionaryを使用することは、並列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処理を最適化できます。

Curtis Chau
テクニカルライター

Curtis Chauは、カールトン大学でコンピュータサイエンスの学士号を取得し、Node.js、TypeScript、JavaScript、およびReactに精通したフロントエンド開発を専門としています。直感的で美しいユーザーインターフェースを作成することに情熱を持ち、Curtisは現代のフレームワークを用いた開発や、構造の良い視覚的に魅力的なマニュアルの作成を楽しんでいます。

開発以外にも、CurtisはIoT(Internet of Things)への強い関心を持ち、ハードウェアとソフトウェアの統合方法を模索しています。余暇には、ゲームをしたりDiscordボットを作成したりして、技術に対する愛情と創造性を組み合わせています。