Upgrade to Pro — share decks privately, control downloads, hide ads and more …

【C#】OrderedDictionaryとは? .NET 9の新機能と そのパフォーマンスを比較

シノラー
January 11, 2025
85

【C#】OrderedDictionaryとは? .NET 9の新機能と そのパフォーマンスを比較

https://petalite-ridge-633.notion.site/OrderedDictionary-NET-9-1789e76890858021b75dc3ac3dc32ca1
上記に検証に使用したコードを載せています。
検証クラスのHairetsuSokudoHikakuクラスのインスタンスを作成し、KensyouStartメソッドを呼び出すことで実行されます。

シノラー

January 11, 2025
Tweet

Transcript

  1. 目次 1. OrderedDictionary とは? 2. OrderedDictionary と Dictionaryの違い 3. OrderedDictionary

    の使い所 4. 速度検証(OrderedDictionary vs Dictionary) 5. まとめ
  2. 1.OrderedDictionary とは? OrderedDictionary は、キーと値のペアを管理するコレクションで、 要素の追加順序を保持 する特性を持っています。 これにより、格納した順序でデータを取り出すことができます。 特徴は以下です。 • 順序保持:要素を追加した順序を保持するため、      要素を格納した順序でアクセスできます。

    • キーの重複禁止 :Dictionary と同様に、キーの重複は許されません。 • パフォーマンス :順序リストの管理が加わるため、         追加・削除時に Dictionary より処理コストが         高くなることがあります。
  3. 2.OrderedDictionaryとDictionaryの違い 1. 順序保持の有無 • OrderedDictionary:要素を追加した順序を保持 • Dictionary:要素の順序は保証されない 2. 要素のアクセス方法 •

    OrderedDictionary:キーまたはインデックスで要素にアクセス可能 • Dictionary:キーのみで要素にアクセス可能 3. パフォーマンスの違い • OrderedDictionary:順序リスト管理が加わるため、追加・削除時の処理がやや遅い • Dictionary:ハッシュテーブルのみを使用するため、高速にアクセス可能 4. 主な用途 • OrderedDictionary:追加順序を保ったままキー検索が必要な場合に使用 • Dictionary:順序が不要で、高速なキー検索が必要な場合に使用
  4. 3.OrderedDictionaryの使い所 • データの追加順序を保持したい場合 ◦ データを追加した順番をそのまま保持して検索・列挙したいときに有効。 ◦ 例: ユーザー入力データやログ情報の順序をそのまま保存して扱いたい場合。 • 順序を利用してデータを操作する場合

    ◦ 順序を意識した処理(先頭・末尾へのアクセスや範囲指定)が必要な場合。 ◦ 例: 時系列データやイベント履歴のように、順序を考慮してデータを処理する場合。 • キーの重複を許さないが、順序も重要な場合 ◦ Dictionaryでは順序が保証されず、 Listではキーの一意性が保証されない場面で便利。 ◦ 例: 設定値や構成情報を順序付きで保持したい場合。 注意点 • データ量が多い場合、順序リストの管理コストが追加されるため、パフォーマンスに注意。 • 追加順序が不要な場合は、単純な Dictionaryのほうが高速で効率的。
  5. 4.速度検証(Dictionary vs OrderedDictionary) 検証環境スペック CPU: 2.60GHz メモリ: 9.8GB OS: Windows

    10 64bit(仮想環境) ストレージ: 100GB コア数: 4 .NETランタイム: Microsoft.WindowsDesktop.App 9.0.0 10万件のデータを検索、追加、削除し処理速度と CPU使用量を測定
  6. 検証対象(検索) • Dictionary[i] ◦ 説明: 指定したキーiをもとにハッシュ値を計算し、データを取得する辞書型のアクセス方法。 ◦ ポイント : 高速な検索が可能だが、衝突が起きた場合の処理が必要。

    ◦ 例:Ordered Dictionary[5]を指定した場合、「 Key:5, Value:”a”」が取得される。 ・初期値 Key:5, Value:”a” Key:6, Value:”b” Key:7, Value:”c” Key:8, Value:”d” Key:9, Value:”e” • OrderedDictionary[i] ◦ 指定した順序リストの位置 iに格納されたデータを取得する方法。 ◦ ポイント : ハッシュ値ではなく、追加された順番に基づいた位置情報で管理される。 ◦ 例:Ordered Dictionary[0]を指定した場合、「 Key:5, Value:”a”」が取得される。 ・初期値 [0] Key:5, Value:”a” [1] Key:6, Value:”b” [2] Key:7, Value:”c” [3] Key:8, Value:”d” [4] Key:9, Value:”e”
  7. 検証対象(検索) • Dictionary.ContainsKey(i) ◦ 説明: 指定したキーiをもとにハッシュ値を計算し、    該当するキーがハッシュテーブル内に存在するかを判定する辞書型のメソッド。 ◦ ポイント :

    高速にキーの存在を確認できるが、     衝突が発生した場合はバケット内のデータを探索する必要がある。 • OrderedDictionary.ContainsKey(i) ◦ 説明: 指定したキーiをもとにハッシュ値を計算し、   該当するキーがハッシュテーブル内に存在するかを判定する辞書型のメソッド。 ◦ ポイント : 検索方法はDictionaryと似ている。      キー検索自体の速度は Dictionaryとほぼ同等。
  8. 検証対象(追加) • Dictionary.Add(Key, Value) ◦ 説明: 指定したキー Key を基にハッシュ値を計算し、 そのハッシュ値からインデックスを計算してハッシュテーブルにデータを追加します。

    ◦ ポイント: ▪ 初期容量: 初期容量が指定されていない場合、 データ量が増えるごとにハッシュテーブルがリサイズされ、 再ハッシュが行われるためパフォーマンスに影響を与えることがあります。 ▪ パフォーマンス : 適切な初期容量を設定することでリサイズ回数を減らし、 効率的なデータ追加が可能になります。 • OrderedDictionary.Add(Key, Value) ◦ 説明: Dictionary.Add と同様の流れでハッシュテーブルにデータを追加し、 その後、順序リストにもデータを追加します。 ポイント: ▪ 初期容量: 初期容量が指定されていない場合、 リサイズの影響でハッシュテーブルと順序リスト両方の処理時間が増加します。 初期容量の指定が重要です。 ▪ パフォーマンス : ハッシュテーブルへの追加に加えて順序リストへの操作があるため、 Dictionary.Add よりも若干処理時間が増加しますが、 初期容量を適切に設定することで効率化が可能です。
  9. 検証対象(削除) • Dictionary.Remove(Key) ◦ 説明: 指定したキー Key を基にハッシュ値を計算し、 対応するインデックスのデータを削除します。 ◦

    ポイント: ハッシュテーブルから直接削除され、追加された順序は考慮されません。 • OrderedDictionary.Remove(Key) ◦ 説明: 指定したキー Key を基にハッシュ値を計算して ハッシュテーブルからデータを削除した後、順序リストからも削除します。 ◦ ポイント: ハッシュテーブルだけでなく順序リストからの削除処理が必要なため、      Dictionary.Remove よりも処理時間が長くなる可能性があります。 • OrderedDictionary.Clear() ◦ 説明: ハッシュテーブルと順序リストの両方をクリアしてデータを完全に削除します。 ◦ ポイント: Dictionary.Clear() と同様の動作ですが、 順序リストが関与するため、内部の処理が増加します。
  10. 検索 速度検証 メモリ使用量 (MB) 8.88 8.69 15 14 処理時間(MS) Dictionary

    .ContainsKey() OrderedDictionary .ContainsKey() 処理名 8.69 13 Dictionary[] 8.67 19 OrderedDictionary[]
  11. 追加(初期容量指定有無) 速度検証 メモリ使用量 (MB) 処理時間(MS) Key 初期容 量 連番 無

    117.55 320 45.81 286 連番 連番 無 有 名前 Dictionary OrderedDictionary OrderedDictionary 117.48 271 45.79 264 連番 有 Dictionary
  12. 追加(キーが連番orランダム) 速度検証 メモリ使用量 (MB) 処理時間(MS) Key 初期容 量 連番 有

    連番 ランダ ム 有 有 名前 Dictionary OrderedDictionary OrderedDictionary 45.79 264 45.78 45.81 286 398 ランダ ム 有 Dictionary 45.78 387
  13. 削除 速度検証 メモリ使用量 (MB) 9.82 9.51 9.09 95 9.34 33

    27 6 処理時間(MS) Dictionary OrderedDictionary OrderedDictionary OrderedDictionary 名前 Remove(i) Remove(i) 論理削除 (Valueのインスタンスの削除フ ラグを更新) 削除方法 Clear
  14. 用語解説(ハッシュ関数) 1. ハッシュ関数 (Hash Function) 説明: 入力データ(キー)を固定長の数値 (ハッシュ値)に変換する関数。 ポイント :

    同じ入力なら同じハッシュ値が生成されるが、異なる入力でも同じハッシュ値が生成されること (衝突)がある。 2. ハッシュ計算 (Hash Calculation) 説明: ハッシュ関数を使用してキーからハッシュ値を算出する処理。 ポイント : • ハッシュ計算自体は非常に高速だが、衝突が多発すると後処理のオーバーヘッドが発生する。 • OrderedDictionary でもキーを使ってハッシュ値が計算されるが、 検索時に順序リストの情報も活用されるため衝突回避がしやすい。 3. ハッシュ値 (Hash Value) 説明: ハッシュ関数によって計算された値。 ポイント : この値を使ってハッシュテーブル内の格納位置を計算する。
  15. 用語解説(順序リスト) 1. 順序リスト (Ordered List) 説明: 追加された順序を保持するリスト。 ポイント : OrderedDictionary

    はこのリストを用いてデータの順序を管理している。 2. 初期容量 (Initial Capacity) 説明: ハッシュテーブルや順序リストの初期サイズを示す設定値。 ポイント : • 初期容量を大きめに設定すると、データ追加時の再割り当て (リサイズ)回数が減るため高速になる。 • 小さい場合はデータ追加が増えると頻繁にリサイズが発生し、パフォーマンス低下の要因となる。 3. エントリ追加時の処理 • 順序リストに追加順に要素 が記録され、参照のための順序が保存されます。 • 同時に、キーを元にハッシュ値を生成し、ハッシュテーブルにもデータが格納されます。 4. データ取得時の処理 • 順序リスト から対象の位置を探索し、対応するハッシュテーブルのインデックスを参照し、該当のデータを取得します。
  16. 用語解説(HashTable) 1. ハッシュテーブル (Hash Table) 説明: ハッシュ値をインデックスとしてデータを格納・管理するデータ構造。 ポイント : 直接インデックスでアクセスできるため、高速な検索が可能。

    2. インデックス (Index) 説明: ハッシュテーブル内のデータ位置を示す番号。 ポイント : ハッシュ値 % テーブルサイズ で計算される。 3. テーブルサイズ (Table Size) 説明: ハッシュテーブルの容量を示す数値。 ポイント : データ量に応じて拡張され、初期容量を設定することでパフォーマンスを最適化できる。 4. リサイズ 説明: ハッシュテーブルの容量が足りない場合、拡張を行う。(通常は 2倍に拡張される)
  17. 用語解説(その他) 1. 衝突 (Collision) 説明: 異なるキーが同じハッシュ値を持つこと。 衝突は要素の追加( Add)時に発生します。 衝突が発生 すると、同じバケット内に複数の要素を格納するため、

    リンクリスト や配列などが構築されます (チェイニング法 )。 ポイント : 同じインデックスに複数のデータが存在する状態であり、衝突解決法が必要となる。 2. 衝突解決法 (Collision Resolution) 説明: 衝突を回避するための方法。 ポイント : 「オープンアドレス法」 (別の場所に再配置 )や「チェイン法」(リストで格納)などがある。
  18. ・検索: (Dictionary[i]) 19 5 ハッシュ 関数 (例) 検索キーに7 をかける。 6

    7 35 42 49 Keyに指定する 値 ハッシュ値 生成 Index生成 (式) ハッシュ値 %TableSize (仮に5とする) 0 2 4 Index 生成 HashTable ・初期値 Key:5, Value:”a” Key:6, Value:”b” Key:7, Value:”c” Key:8, Value:”d” Key:9, Value:”e” Key:10, Value:”f” 1 3 2 3 Key Value Index リンクリスト Key:6, Value:”b” Key:7, Value:”c” Key:8, Value:”c” Key:9, Value:”c” Key:10, Value:”f” リンクリストのアドレス (Add時に衝突発生 ) 0 Key:5, Value:”a” 4
  19. ・検索:(OrderedDictionary[i]) 20 1 2 3 [i]に指定 する値 ・初期値 [0] Key:5,

    Value:”a” [1] Key:6, Value:”b” [2] Key:7, Value:”c” [3] Key:8, Value:”d” [4] Key:9, Value:”e” 0 10 1 11 2 12 3 13 4 14 HashTable 10 Key:5, Value:”a” 11 Key:6, Value:”b” 12 Key:7, Value:”c” 13 Key:8, Value:”c” 14 Key:9, Value:”c” 順序リストの Index 順序リスト Index HashTableの Index
  20. ・検索: (ContainsKey(Key)) 22 5 ハッシュ 関数 (例) 検索キーに7 をかける。 6

    7 35 42 49 Keyに指定する 値 ハッシュ値 生成 Index生成 (式) ハッシュ値 %TableSize (仮に5とする) 0 2 4 Index 生成 HashTable ・初期値 Key:5, Value:”a” Key:6, Value:”b” Key:7, Value:”c” Key:8, Value:”d” Key:9, Value:”e” Key:10, Value:”f” 1 3 2 3 Key Value Index リンクリスト Key:6, Value:”b” Key:7, Value:”c” Key:8, Value:”c” Key:9, Value:”c” Key:10, Value:”f” リンクリストのアドレス (Add時に衝突発生 ) 0 Key:5, Value:”a” 4 存在する:true 存在しない:false
  21. ・追加:Dictionary 24 ハッ シュ 関数 (例) 検索キー に7をか ける。 11

    77 以下を追加 Key;11, Value:”g” Index生 成 (式) ハッシュ値 %TableSize (リサイズの 結果今回は 6とする) 5 Index 生成 HashTable ・初期値 Key:5, Value:”a” Key:6, Value:”b” Key:7, Value:”c” Key:8, Value:”d” Key:9, Value:”e” Key:10, Value:”f” 1 3 2 3 リンクリスト Key:6, Value:”b” Key:7, Value:”c” Key:8, Value:”c” Key:9, Value:”c” Key:10, Value:”f” リンクリストのアドレス (Add時に衝突発生 ) 0 Key:5, Value:”a” 4 HashTa bleのサ イズ確 認。必要 に応じリ サイズ、 再ハッ シュ ハッシュ 値生成 Key:10, Value:”f” 5 Index5に 追加され る 衝突が発 生した場 合、リンクリ ストに追加
  22. ・追加:OrderedDictionary 基本的な流 れは Dictionary と一緒 0 0 1 1 2

    2 3 3 4 4 順序リスト 5 5 順序リストの Index HashTableの Index HashTableへ の追加完了 後、順序リスト へ追加
  23. 追加処理についての考察 1. なぜOrderedDictionaryの方が遅いのか? • ハッシュテーブルに追加 する処理はDictionaryと同じですが、順序リストにも追加 するため、 リスト管理のオーバーヘッドが発生します。 • 追加ごとにリストサイズが拡張される場合、再確保やデータ移動が発生し、処理が遅くなります。

    2. 初期容量指定なしだと遅い理由 • 初期容量が不足すると、データ追加の過程でハッシュテーブルやリストが自動的にリサイズされます。 • リサイズでは内部データを再配置するため、処理時間が増加します。 3. Keyがランダムな場合の遅さの理由 • ランダムなキーでは、ハッシュ衝突 が発生しやすくなり、 同じバケット内に複数のデータが格納されます。 • 衝突が発生すると、バケット内のリストや配列を線形探索 するため、処理時間が増加します。
  24. 削除処理についての考察 1. Clear() メソッドについて • Dictionary と OrderedDictionary の Clear()

    メソッドは、 全要素を一括削除するため、処理時間は高速です。 • 実際の検証結果でも、Clear() の処理時間は非常に短く、一括で全要素を初期化できています。 2. 個別削除 (Remove(Key)) について • Dictionary は、ハッシュ値をもとにバケットを特定して削除するため、高速に削除できます。 • OrderedDictionary は、ハッシュテーブルの管理に加えて順序リストの管理も必要なため、 削除のコストが高くなる場合があります。 ※ 論理削除を行う場合は、物理削除に比べて処理が高速になります。
  25. 5.まとめ • OrderedDictionaryの特徴 ◦ 順序を保持しつつ、キーと値のペアを効率的に管理。 ◦ 順序を意識したデータ操作に最適。 • Dictionaryとの違い ◦

    順序保持 : OrderedDictionaryは順序を保持、Dictionaryは順序を保証しない。 ◦ パフォーマンス : OrderedDictionaryは順序リスト管理が加わるため、 追加・削除でやや処理コストが増加。 • 検証結果からの学び ◦ 初期容量を適切に設定することでパフォーマンスの最適化が可能。 ◦ ランダムキーの追加は衝突を引き起こしやすく、パフォーマンス低下に注意。 ◦ OrderedDictionaryは順序リストの管理が加わるため、用途に応じて使い分けが重要。 • 使い所 ◦ データの順序を保持したい場合や順序を意識した処理が必要な場合に活用。 ◦ 大量データや高速な処理が必要な場合は Dictionaryが適している。