枚举 Dictionary.Values 与字典本身
Enumerate Dictionary.Values vs Dictionary itself
我正在 GitHub 上探索 ASP.NET 核心的来源,看看 ASP.NET 团队使用了什么样的技巧来加速框架。我看到了让我感兴趣的东西。在 ServiceProvider 的源代码中,在 Dispose 实现中,他们枚举了一个字典,并添加了注释以指示性能技巧:
private readonly Dictionary<IService, object> _resolvedServices = new Dictionary<IService, object>();
// Code removed for brevity
public void Dispose()
{
// Code removed for brevity
// PERF: We've enumerating the dictionary so that we don't allocate to enumerate.
// .Values allocates a KeyCollection on the heap, enumerating the dictionary allocates
// a struct enumerator
foreach (var entry in _resolvedServices)
{
(entry.Value as IDisposable)?.Dispose();
}
_resolvedServices.Clear();
}
字典这样枚举有什么区别?
foreach (var entry in _resolvedServices.Values)
{
(entry as IDisposable)?.Dispose();
}
它对性能有影响吗?或者是因为分配一个 ValueCollection 会消耗更多的内存?
没错,这是关于内存消耗的。差异实际上在评论中得到了很好的描述:访问 Dictionary<TKey, TValue>
will allocate a ValueCollection
的 Value
属性,这是一个 class(引用类型),在堆。
foreach
'遍历字典本身导致调用 GetEnumerator()
which returns an Enumerator
。这是一个 struct
,将分配在堆栈上而不是堆上。
我正在 GitHub 上探索 ASP.NET 核心的来源,看看 ASP.NET 团队使用了什么样的技巧来加速框架。我看到了让我感兴趣的东西。在 ServiceProvider 的源代码中,在 Dispose 实现中,他们枚举了一个字典,并添加了注释以指示性能技巧:
private readonly Dictionary<IService, object> _resolvedServices = new Dictionary<IService, object>();
// Code removed for brevity
public void Dispose()
{
// Code removed for brevity
// PERF: We've enumerating the dictionary so that we don't allocate to enumerate.
// .Values allocates a KeyCollection on the heap, enumerating the dictionary allocates
// a struct enumerator
foreach (var entry in _resolvedServices)
{
(entry.Value as IDisposable)?.Dispose();
}
_resolvedServices.Clear();
}
字典这样枚举有什么区别?
foreach (var entry in _resolvedServices.Values)
{
(entry as IDisposable)?.Dispose();
}
它对性能有影响吗?或者是因为分配一个 ValueCollection 会消耗更多的内存?
没错,这是关于内存消耗的。差异实际上在评论中得到了很好的描述:访问 Dictionary<TKey, TValue>
will allocate a ValueCollection
的 Value
属性,这是一个 class(引用类型),在堆。
foreach
'遍历字典本身导致调用 GetEnumerator()
which returns an Enumerator
。这是一个 struct
,将分配在堆栈上而不是堆上。