web-dev-qa-db-ja.com

最速のC ++マップ?

Std :: mapは順序付けられたマップなので、値を挿入するたびに、マップはアルゴリズムを使用してアイテムを内部的にソートしますが、これには時間がかかります。

私のアプリケーションは、一定の間隔でいくつかのアイテムに関する情報を取得します。

このアプリは、次のように定義されたマップを保持しています。

::std::map<DWORD, myItem*>

最初は、すべてのアイテムが「新規」と見なされます。 「アイテム」オブジェクトが割り当てられ、このマップに追加されています。そのIDとポインターが関連付けられています。

「新しい」アイテムではない場合(このオブジェクトの更新のみ)、アプリは、指定されたIDを使用してマップでオブジェクトを検索し、更新する必要があります。

ほとんどの場合、更新を取得します。

私の質問は:
より高速なマップ実装はありますか、またはこれを引き続き使用する必要がありますか?
私はunordered_mapを使用した方がよいですか?

23
Poni

Unordered_mapを使用した方がよいですか?

たぶん。

std:mapは、バランスの取れたツリーとして実装する必要があるため、O(log n)で一貫したパフォーマンスを提供します。だが std:unordered_mapは、O(1)パフォーマンス(良いハッシュ関数とハッシュバケット間でのキーの分散)を提供する)が可能なハッシュテーブルとして実装されますが、O(n)(1つのハッシュバケット内のすべてのものとリストに展開されます)通常、これらの極端な中間の何かが予想されます。

したがって、常に妥当なパフォーマンス(O(log n))を得ることができます。またはyoは、ハッシュで良好なパフォーマンスを得るためにすべてが揃うようにする必要があります。

そのような質問と同様に、1つのアプローチに取り組む前に測定する必要があります。データセットが大きくない限り、大きな違いはないことに気付くでしょう。

41
Richard

重要な警告:マップのパフォーマンスがアプリケーションのパフォーマンスに実質的に影響することを測定していない限り(そして、質問でそうしていないことが示唆されている場合を除く)、マップの検索と更新に大きな時間を費やしています)それをより速くすることに悩む。 std::map(またはstd::unordered_mapまたは利用可能なhash_map実装)を使用してください。アプリケーションを1%高速化することは、おそらく努力する価値がありません。代わりに、バグのないようにしてください。

リチャードの答えをエコーする:measure実際のクラスと実際のデータを使用した、異なるマップ実装でのパフォーマンス。

追加のメモ:

  • 予想コスト(ハッシュマップは通常それが低い)、最悪の場合のコスト(バランスの取れたバイナリツリーではO(logn)ですが、挿入がハッシュ配列の再割り当てをトリガーした場合のハッシュマップでははるかに高い)と償却コスト(合計コストを数値で割った値)の違いを理解します操作または要素の;新しい要素と既存の要素の比率のようなものに依存します)。あなたの場合、どちらがより制約的であるかを見つける必要があります。たとえば、非常に低いレイテンシ制限を守る必要がある場合、ハッシュマップの再割り当ては多すぎる可能性があります。

  • 実際のボトルネックがどこにあるかを調べます。マップでの検索のコストは、たとえば、 IOコスト。

  • より特殊なマップ実装を試してください。たとえば、マップのキーについて何か知っていれば、多くのことが得られます。一般的なマップ実装の作成者は、そのような知識を持っていません。

あなたの例(強くクラスター化されている32ビットの符号なし整数キー、たとえば順次割り当てられている)では、基数ベースのアプローチを使用できます。 Very簡単な例(レシピとして使用する準備ができていないため、イラストとしてそれを脅かしてください):

Item *sentinel[65536];  // sentinel page, initialized to NULLs.
Item (*pages[65536])[65536];  // list of pages,
                              // initialized so every element points to sentinel

次に、検索は次のように簡単です。

Item *value = pages[index >> 16][index & 0xFFFF];

新しい値を設定する必要がある場合:

if (pages[index >> 16] == sentinel) {
  pages[index >> 16] = allocate_new_null_filled_page();
}
pages[index >> 16][index & 0xFFFF] = value;
  • マップの実装を微調整します。

    • 例えば。すべてのhash_mapは、事前におおよその要素数を知りたいと思っています。これは、ハッシュテーブルの不必要な再割り当てと(場合によっては)すべてのキーの再ハッシュを回避するのに役立ちます。

    • 上記の特別な例では、確かに異なるページサイズ、または3レベルバージョンを試してみます。

    • 一般的な最適化は、小さなオブジェクトの複数の割り当てを回避するために、特殊なメモリアロケータを提供することです。

11

アイテムを挿入または削除するたびに、メモリの割り当て/割り当て解除に多くのコストがかかります。代わりに、次のようなアロケーターを使用できます: https://github.com/moya-lang/Allocator std :: mapを2倍高速化著者は言うが、特に他のSTLコンテナの場合はさらに速くなることがわかりました。

1
no one special