San*_*Cha 9 .net c# performance dictionary
我有两个具有不同值类型的字典:Dictionary<int, string[]>
和Dictionary<int, int[]>
. 假设我们在循环中生成随机数组并将它们插入到字典中(在 C# 中)。
var d1 = new Dictionary<int, string[]>();
var d2 = new Dictionary<int, int[]>();
var sw = Stopwatch.StartNew();
for (int i = 0; i < 40000000; i++)
{
string[] sarr = new string[10];
for (int j = 0; j < 10; j++)
{
sarr[j] = j.ToString();
}
int[] iarr = new int[10];
for (int j = 0; j < 10; j++)
{
iarr[j] = j;
}
d1[i] = sarr; // (1)
d2[i] = iarr; // (2)
}
sw.Stop();
Run Code Online (Sandbox Code Playgroud)
注意 for 循环的最后两行。当我运行上面的代码时,在我的机器上大约需要 13.9 秒。现在,当我只注释掉 (1) 时,大约需要 13.7 秒。如果我只注释掉 (2),那么大约需要 20 秒。换句话说,通过删除(2)它变得更慢!我重复了多次,我可以确认行为是一致的。
谁能解释一下这怎么可能?
我做这个实验是因为我注意到即使我在两个字典中使用相同的键,插入string[]
也比插入慢int[]
。我想知道为什么 insertstring []
也可能比 insert 慢int[]
。
所以我的问题是双重的:(1)为什么从上面的代码中删除一行会使事情变慢,(2)为什么插入string[]
比插入慢int[]
?
仅供参考,我使用的是最新的 .NET 5 (5.0.103)。我在 Windows 和 Linux 上都尝试了代码,行为是一样的。使用调试或发布模式时,我始终看到相同的问题。
当我将注释掉的版本与原始版本的 IL 进行比较时,注释掉的版本没有set_Item
按预期调用字典的功能。其他事情或多或少是相同的。
IL_0079: ldloc.1 // dictionary2
IL_007a: ldloc.3 // key
IL_007b: ldloc.s numArray
IL_007d: callvirt instance void class [System.Collections]System.Collections.Generic.Dictionary`2<int32, int32[]>::set_Item(!0/*int32*/, !1/*int32[]*/)
IL_0082: nop
Run Code Online (Sandbox Code Playgroud)
例如,当我注释掉(2)时,上面的部分被删除了。
为了帮助重现这个问题,我用 Benchmark.NET 创建了一个简单的 repo:https : //github.com/sangkilc/TestDictionary。在这个 repo 中,我减少了迭代次数(从 40M 到 4M),因为它花费的时间太长。
在我的机器上,结果是:
.NET Core SDK=5.0.103
[Host] : .NET Core 5.0.3 (CoreCLR 5.0.321.7212, CoreFX 5.0.321.7212), X64 RyuJIT
DefaultJob : .NET Core 5.0.3 (CoreCLR 5.0.321.7212, CoreFX 5.0.321.7212), X64 RyuJIT
| Method | Mean | Error | StdDev |
|--------- |--------:|---------:|---------:|
| TestBoth | 1.269 s | 0.0222 s | 0.0208 s |
| TestOne | 1.381 s | 0.0257 s | 0.0241 s |
Run Code Online (Sandbox Code Playgroud)
根据@TheodorZoulias 的观察,如果我修改d2
为二维数组,则差异变得更加显着:
| Method | Mean | Error | StdDev |
|--------- |--------:|---------:|---------:|
| TestBoth | 1.137 s | 0.0195 s | 0.0163 s |
| TestOne | 1.373 s | 0.0246 s | 0.0345 s |
Run Code Online (Sandbox Code Playgroud)
这不是答案,只是想展示一些图片
我在发布中针对您的两个场景编译了代码:
请注意,我删除了Stopwatch
相关代码,因为我们只对Dictionary
.
我的机器上有dotTrace,所以我得到了一些分析结果(逐行)。
对于这两种情况:
对于仅 (1) 的场景:
既然您提到模式是一致的,我只运行了一次分析。
从结果中,我们可以看出相关的函数Dictionary
并不是所谓的“奇怪的性能行为”的主要贡献者,GC可能是。
归档时间: |
|
查看次数: |
251 次 |
最近记录: |