我正在对几个String dicctionaries做一些基准测试,因为我想知道如何执行不同的配置,我很惊讶普通的Dictionary更快。可能是因为我错过了一些概念或者我做错了什么,但这些都是我得到的结果:
Collection: 2147482 items.
Random Keys: 1000 keys.
Normal dicctionary
Add 1000 items: 573ms.
Get 1000 keys: 0ms.
Normal Dicctionary with OrdinalIgnoreCase comparer
Add 1000 items: 642ms.
Get 1000 keys: 0ms.
Normal Dicctionary with InvariantCultureIgnoreCase comparer
Add 1000 items: 1661ms.
Get 1000 keys: 0ms.
Sorted dicctionary
Add 1000 items: 11996ms.
Get 1000 keys: 5ms.
Sorted dicctionary with OrdinalIgnoreCase comparer
Add 1000 items: 11097ms.
Get 1000 keys: 5ms.
Sorted dicctionary with InvariantCultureIgnoreCase comparer
Add 1000 items: 9814ms.
Get 1000 keys: 5ms.
这是我用来测试它的代码:
static void Main(string[] args)
{
String[] col = GenerateCollectionUnsorted(Int32.MaxValue / 1000).ToArray();
Int32 len = col.Length;
Console.WriteLine("Collection:\t\t" + len.ToString() + " items.");
String[] randomKeys = GetRandomKeys(col, 1000);
Console.WriteLine("Random Keys:\t\t" + randomKeys.Length.ToString() + " keys.");
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine();
Console.WriteLine("Normal dicctionary");
TestDic(col, randomKeys, new Dictionary<String, String>());
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine();
Console.WriteLine("Normal Dicctionary with OrdinalIgnoreCase comparer");
TestDic(col, randomKeys, new Dictionary<String, String>(StringComparer.OrdinalIgnoreCase));
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine();
Console.WriteLine("Normal Dicctionary with InvariantCultureIgnoreCase comparer");
TestDic(col, randomKeys, new Dictionary<String, String>(StringComparer.InvariantCultureIgnoreCase));
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine();
Console.WriteLine("Sorted dicctionary");
TestDic(col,randomKeys, new SortedDictionary<String,String>());
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine();
Console.WriteLine("Sorted dicctionary with OrdinalIgnoreCase comparer");
TestDic(col, randomKeys, new SortedDictionary<String, String>(StringComparer.OrdinalIgnoreCase));
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine();
Console.WriteLine("Sorted dicctionary with InvariantCultureIgnoreCase comparer");
TestDic(col, randomKeys, new SortedDictionary<String, String>(StringComparer.InvariantCultureIgnoreCase));
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("\nEnd");
Console.ReadKey(true);
}
static void TestDic(String[] col, String[] randomKeys, IDictionary<String,String> dic)
{
Stopwatch crono = new Stopwatch();
crono.Start();
foreach (String s in col)
dic.Add(s, s);
crono.Stop();
Console.WriteLine("\tAdd "+randomKeys.Length.ToString()+" items:\t\t" + crono.ElapsedMilliseconds.ToString() + "ms.");
crono.Reset();
crono.Start();
String sv;
foreach (var rk in randomKeys)
{
sv = dic[rk];
sv.ToString();
}
crono.Stop();
Console.WriteLine("\tGet " + randomKeys.Length.ToString() + " keys:\t\t" + crono.ElapsedMilliseconds.ToString() + "ms.");
}
static String[] GetRandomKeys(String[] col, Int32 count)
{
Random ran = new Random(DateTime.Now.Millisecond);
List<Int32> indexSelection = new List<int>();
List<String> selection = new List<string>();
Int32 len = col.Length;
while (indexSelection.Count < count)
{
Int32 value = ran.Next(0, len - 1);
if (!indexSelection.Contains(value))
{
indexSelection.Add(value);
selection.Add(col[value]);
}
}
return selection.ToArray();
}
static IEnumerable<String> GenerateCollection(Int32 count)
{
for (int i = 0; i < count; i++)
{
yield return i.ToString("X").PadLeft(5, '0');
}
}
static IEnumerable<String> GenerateCollectionUnsorted(Int32 amount)
{
for (int i = 0; i < amount / 2; i++)
{
yield return i.ToString("X").PadLeft(5, '0');
yield return (amount-i).ToString("X").PadLeft(5, '0');
}
}
知道为什么会这样吗?
编辑1:我的理解是,排序的字典会更慢地添加项目,并且因为集合已经排序而更快地获取它们。而且,将字符串与OrdinalIgnoreCase或InvariantCultureIgnoreCase进行比较应该比正常比较更快,因此搜索应该更快。但也许我的理解是完全错误的:D
提前致谢。
编辑2:由于好奇心,我对字符串比较进行了一些测试:
Collection: 2147482 items.
Random Keys: 1000 keys.
CurrentCulture
LookUp: 158209ms.
CurrentCultureIgnoreCase
LookUp: 160710ms.
InvariantCulture
LookUp: 132765ms.
InvariantCultureIgnoreCase
LookUp: 133409ms.
Ordinal
LookUp: 36115ms.
OrdinalIgnoreCase
LookUp: 36329ms.
答案 0 :(得分:3)
因为只有普通字典和默认比较器实际上是普通字典,所以其他字典都是排序字典。
所以,结果非常一致。
修复后,结果会有所不同。 :)
在添加项目时,排序字典的速度较慢,因为它们需要进行排序,但在获取项目时速度并不快。搜索二叉树很快,但搜索常规字典使用的哈希列表更快。当二叉树增长时,将会有更多步骤来定位每个项目,而字典主要通过添加更多桶来增长,因此比较的数量几乎不受影响。
比较字符串Ordinal
比常规(CurrentCulture
)比较快,OrdinalIgnoreCase
比CurrentCultureIgnoreCase
快,但不确定OrdinalIgnoreCase
是快于CurrentCulture
。 InvariantCulture
比较并不比常规比较快,它只是使用不同的文化。顺序比较快得多的原因是它根本不需要为文化环境而烦恼。
顺便说一下,我注意到GetRandomKeys方法中有一个错误。它永远不会选择最后一项,因为你得到一个0和长度为2的随机数。
答案 1 :(得分:3)
来自MSDN documentation on SortedDictionary
:
SortedDictionary<TKey, TValue>
泛型类是一个带有O(log n)检索的二叉搜索树,其中n是字典中元素的数量。
使用其密钥检索值非常快,接近于O(1),因为
Dictionary<TKey, TValue>
类是作为哈希表实现的。
因此,Dictionary
在许多情况下可以胜过SortedDictionary
并不奇怪。
答案 2 :(得分:2)
我没有理解为什么你会对结果感到惊讶。
“normal”/ unsorted显然会比排序字典快,因为已排序的字典必须执行额外的操作。
具有额外选项的两个“普通”都需要额外处理。