これは、std :: set <>が既に完全に優れた比較演算子を持っているという事実に基づく愚かな質問かもしれませんが、私は特定のユースケースの最適化があり、自分自身を傷つけないようにしたいと思いますどういうわけか。"平坦化" std :: set <std::string>の保存と比較は可能ですか?
本質的には、入力としてstd :: set &をとる高価な操作があります。私はその後、同じ入力がすでに渡されている場合、私はちょうど結果を返すことができますので、これは私が
std::map<std::set<std::string>, Result*>
でやっているセットのコピーを(保存する必要がない。操作の結果をキャッシュし、よ同じ操作が何千回も連続して呼び出される可能性が非常に高いので、キャッシュされたstd :: setは> 99%の時間内に検出されます。私は最近、渡された文字列で特定の文字が無効であるという事実に基づいて、少し改良があると思ったものを試しました。私はstd :: setを単一の文字列に平坦化しました。コンポーネント文字列は ': '文字。私のstd :: mapは
になります3210std::map<std::string, Result*>
と呼ばれ、操作が呼び出されるたびに、そのセットは平坦化され、単一の文字列がキャッシュ内で検索されます。
私は実際にパフォーマンスの向上に驚いていました。私のテストでは、5つの文字列、それぞれ30文字の長さ、10,000,000回の実行を含むstd :: setsを使用しました。私のワークステーションでは、それぞれの実行のための時間がそれもセットにすべての呼び出しを平坦化するオーバーヘッドで、第2の方法は大幅に改善され、と思われ
std::map<std::set<std::string>, Result*> : 138.8 seconds
std::map<std::string, Result> : 89.2 seconds
ました。私の質問は、なぜでしょうか? std :: setの実装者が意図的に回避されている(つまり、より大きな文字列でひどいヒープフラグメンテーションを引き起こす可能性がある)可能性がありますか?単純にセット内の個々の文字列が異なる場所にあり、別々に比較される必要があるからです?私は足で自分を撃っていますか?このようなパフォーマンスを向上させるためには、この特定のケースでの改善があまりにも明白なように思えます。
同じパラメータで時間の99%の関数を呼び出すと、関数自体ではなく呼び出し元に問題があると言います。とにかく、あなたのセットに何らかの 'id'を追加することはできないので、メソッドは' set'の代わりに 'id'を比較するだけです。あなたが渡しているセットが頻繁にそれを変えないように思えます。 – user463035818
私は少し単純すぎましたが、関数への入力はstd :: setと2つの別々のメッセージを比較することです。このセットは、比較の前にメッセージに適用される変換を記述しています。この変換はコストのかかる部分です(適用は簡単です)。ほとんどの場合、セットは変更されませんが、メッセージはほとんど常に異なります。理想的には、呼び出し元に何らかの形で変換のハンドルを取得させてから、比較を呼び出すときにはセットの代わりにハンドルを使用することになります。残念ながら、これは既存のコードを置換する必要があります。 – Kevin
セパレータを実際の文字列の一部にすることはできません。また、パフォーマンスがstd :: unordered_mapまたはstd :: unordered_setでbencmarkすることを忘れることもありません。ただし、文字列全体を読み取ってハッシュを生成しなければならないため、文字列は常に最善の型であるとは限りませんが、opreator <は先に停止することができます。 – SteakOverflow