Closed gaufung closed 2 weeks ago
在 C#
中有 ReadOnlyDictionary
, ImmutableDictionary
和 ForzenDictionary
三种类型,那么它们在功能和性能上有什么区别呢?
[Benchmark]
public void Create_ReadOnlyDictionary() {
var dictionnary = new Dictionary<string, Goat>();
for (int i = 0; i < 1000000; i++) {
dictionnary.Add(i.ToString(), new Goat{Name = i.ToString()});
}
var result = new ReadOnlyDictionary<string, Goat>(dictionnary);
}
[Benchmark]
public void Create_ImmutableDictionary() {
var dictionnary = new Dictionary<string, Goat>();
for (int i = 0; i < 1000000; i++) {
dictionnary.Add(i.ToString(), new Goat{Name = i.ToString()});
}
var result = dictionnary.ToImmutableDictionary();
}
[Benchmark]
public void Create_FrozenDictionary() {
var dictionnary = new Dictionary<string, Goat>();
for (int i = 0; i < 1000000; i++) {
dictionnary.Add(i.ToString(), new Goat{Name = i.ToString()});
}
var result = dictionnary.ToFrozenDictionary();
}
Benchmark 的结果如下
Method | Mean | Error | StdDev | Gen0 | Gen1 | Gen2 | Allocated |
---|---|---|---|---|---|---|---|
Create_ReadOnlyDictionary | 967.4 us | 742.6 us | 40.70 us | 220.7031 | 220.7031 | 220.7031 | 1.72 MB |
Create_ImmutableDictionary | 6,556.5 us | 27,352.5 us | 1,499.28 us | 218.7500 | 218.7500 | 218.7500 | 2.33 MB |
Create_FrozenDictionary | 2,985.9 us | 7,518.3 us | 412.10 us | 359.3750 | 359.3750 | 359.3750 | 2.6 MB |
可以看出 ReadOnlyDictionary
创建最快,FrozenDictionary
次之,最后是 ImmutableDictionary
最慢。 原因是什么呢? ReadOnlyDictionary
是复用了底层 Dictionary
结构,只不过丢弃了修改的操作,比如 Add
等,所以如果还能访问底层的 Dictionary
, 也是有机会去修改 ReadOnlyDictionary
; ImmutableDictionary
是 Immutable
的实现,当你在修改这个字典的时候,它会创建一个新的字典,而保持原有的不变;
[Benchmark]
public void TryGetValue_ReadOnlyDictionary() {
for (int i = 0; i < 1000000; i++) {
var index = Random.Shared.Next(0, N);
_readOnlyDictionary.TryGetValue(index.ToString(), out var value);
}
}
[Benchmark]
public void TryGetValue_ImmutableDictionary() {
for (int i = 0; i < 1000000; i++) {
var index = Random.Shared.Next(0, N);
_immutableDictionary.TryGetValue(index.ToString(), out var value);
}
}
[Benchmark]
public void TryGetValue_FrozenDictionary() {
for (int i = 0; i < 1000000; i++) {
var index = Random.Shared.Next(0, N);
_frozenDictionary.TryGetValue(index.ToString(), out var value);
}
}
Benchmark 结果如下
Method | Mean | Error | StdDev | Gen0 | Allocated |
---|---|---|---|---|---|
TryGetValue_ReadOnlyDictionary | 676.7 us | 502.6 us | 27.55 us | 31.2500 | 303.14 KB |
TryGetValue_ImmutableDictionary | 1,514.5 us | 845.4 us | 46.34 us | 31.2500 | 303.12 KB |
TryGetValue_FrozenDictionary | 391.3 us | 1,828.4 us | 100.22 us | 32.7148 | 303.13 KB |
可以看出 ReadOnlyDictionary
创建最快,FrozenDictionary
次之,最后是 ImmutableDictionary
最慢。之前我们讨论 ImmutableDictionary
是不可变的,可以在多线程中使用。但是 FrozenDictionary
也是不可变的字段,但是它在读取的数据的性能上比 ImmutableDicionary
好很多。
所以,我们可以得到结论,在多线程环境中, ReadOnlyDictionary
并不是好的类型,ImmutableDictionary
可以在多线程写操作中发挥作用,FrozenDictionary
在多线程读操作中发挥作用。
https://goatreview.com/choosing-best-immutable-dictionary-csharp-projects/