Guid
をのインデックスとして使用Dictionary
する場合、オブジェクトを使用するのGuid
と、Guid の文字列表現を使用するのとのどちらがよいでしょうか?
オブジェクトを使用するために文字列を使用していたいくつかのコードをリファクタリングnew Guid()
しました。しかし、それはパフォーマンスの問題が何であるか疑問に思いました. (コレクションはかなり小さいですが、何度も繰り返されます。)
Guid
をのインデックスとして使用Dictionary
する場合、オブジェクトを使用するのGuid
と、Guid の文字列表現を使用するのとのどちらがよいでしょうか?
オブジェクトを使用するために文字列を使用していたいくつかのコードをリファクタリングnew Guid()
しました。しかし、それはパフォーマンスの問題が何であるか疑問に思いました. (コレクションはかなり小さいですが、何度も繰り返されます。)
比較はより単純であるため、Guid
より速くなるはずです-ほんの数バイトです。文字列には逆参照が含まれ、さらに多くの作業が必要です。
もちろん、プロファイリングできます ;-p
証拠:
Searching for 7f9b349f-f36f-94de-ad96-04279ddf6ecf
As guid: 466; -1018643328
As string: 512; -1018643328
Searching for 870ba465-08f2-c872-cfc9-b3cc1ffa09de
As guid: 470; 1047183104
As string: 589; 1047183104
Searching for d2376f8a-b8c9-4633-ee8e-9679bb30f918
As guid: 423; 1841649088
As string: 493; 1841649088
Searching for 599889e8-d5fd-3618-4c4f-cb620e6f81bb
As guid: 488; -589561792
As string: 493; -589561792
Searching for fb64821e-c541-45f4-0fd6-1c772189dadf
As guid: 450; 1389733504
As string: 511; 1389733504
Searching for 798b9fe5-ba15-2753-357a-7637161ee48a
As guid: 415; 779298176
As string: 504; 779298176
Searching for 12ba292e-8e59-e5d0-7d04-e811a237dc21
As guid: 457; 558250944
As string: 564; 558250944
Searching for 05b3ce14-dfbf-4d3a-1503-ced515decb81
As guid: 413; 1658205056
As string: 504; 1658205056
Searching for 8db4a556-0a65-d8cb-4d0d-0104245d18b8
As guid: 415; 696231936
As string: 506; 696231936
Searching for c49cf80c-5537-fba5-eebd-8ad21bba09c4
As guid: 459; 2100976384
As string: 557; 2100976384
に基づく:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
static class Program
{
static void Main()
{
Random rand = new Random(123456);
int COUNT = 1000;
Dictionary<Guid, int> guids = new Dictionary<Guid, int>(COUNT);
Dictionary<string, int> strings = new Dictionary<string, int>(
COUNT, StringComparer.Ordinal);
byte[] buffer = new byte[16];
for (int i = 0; i < COUNT; i++)
{
rand.NextBytes(buffer);
Guid guid = new Guid(buffer);
int val = rand.Next();
guids.Add(guid, val);
strings.Add(guid.ToString(), val);
}
for(int i = 0 ; i < 10 ; i++) {
int index = rand.Next(COUNT);
Guid guid = guids.Keys.Skip(index).First();
Console.WriteLine("Searching for " + guid);
int chk = 0;
const int LOOP = 5000000;
Stopwatch watch = Stopwatch.StartNew();
for (int j = 0; j < LOOP; j++)
{
chk += guids[guid];
}
watch.Stop();
Console.WriteLine("As guid: " + watch.ElapsedMilliseconds
+ "; " + chk);
string key = guid.ToString();
chk = 0;
watch = Stopwatch.StartNew();
for (int j = 0; j < LOOP; j++)
{
chk += strings[key];
}
watch.Stop();
Console.WriteLine("As string: " + watch.ElapsedMilliseconds
+ "; " + chk);
}
Console.ReadLine();
}
}
コレクションはかなり小さいですが、何度も反復されます
反復している場合、キー間の比較はありません。キーで追加/変更または検索する場合、キーがハッシュされ、ハッシュが比較されます。ハッシュが等しい場合にのみ、キーが比較されます。
したがって、多くのハッシュ衝突を伴う巨大な辞書で多くのキーベースの操作を実行していない限り、キー間の比較の速度は大きな要因にはなりません。
私の最初の考えは、Guid
オブジェクトの方が速いということでしたが、入力を文字列として取得し、GUID (頻繁に変更されない) の小さなコレクション (ハッシュセット) で検索する必要がある場合は、それらを格納する方が速いかもしれません。文字列として、次の理由によります。
GUID ディクショナリで文字列を検索するには、文字列を解析し (エラー チェックなどを含む)、Guid
構造を作成し、ハッシュ コードを取得し、ハッシュ ルックアップを実行し、GUID バイトの最終的な比較を行う必要があります。
String-Dictionary で文字列を検索するには、文字列のハッシュを作成し (おそらくGuid
構造体を作成するよりも高速です)、ハッシュを検索して、1 つの文字列比較を行う必要があります。たとえば、多くの GUID がコレクションにないと予想される場合、ハッシュ比較はしばしば失敗し、文字列比較を行う必要さえありません (上記のポイント 1 の GUID 比較よりも少し時間がかかります)。
入力として既に Guid 構造を持っている場合 (たとえば、入力文字列の有効性チェックを行った場合など) はもちろん、それらを辞書のインデックスとして再利用する方がはるかに優れています。
BUT : 設計の明確さ (すべてのコードの 99% でパフォーマンスよりもはるかに重要です) の観点から、構造を使用Guid
し、実際にパフォーマンスの問題が発生した場合にのみ構造を変更する必要があります (プロファイリングにより、利点が得られることが示されます)。文字列ソリューションの)。