Lou*_*Lou 6 .net clr lambda garbage-collection micro-optimization
我今天看到了这个关于ConcurrentDictionary方法的一些性能差异的问题,我认为这是一个过早的微优化。
然而,经过一番思考,我意识到(如果我没记错的话),每次我们将 lambda 传递给一个方法时,CLR 都需要分配内存,传递适当的闭包(如果需要),然后过一段时间再收集它.
有以下三种可能:
没有闭包的 Lambda:
// the lambda should internally compile to a static method,
// but will CLR instantiate a new ManagedDelegate wrapper or
// something like that?
return concurrent_dict.GetOrAdd(key, k => ValueFactory(k));
Run Code Online (Sandbox Code Playgroud)带闭包的 Lambda:
// this is definitely an allocation
return concurrent_dict.GetOrAdd(key, k => ValueFactory(k, stuff));
Run Code Online (Sandbox Code Playgroud)外部检查(例如检查锁定前的条件):
// no lambdas in the hot path
if (!concurrent_dict.TryGetValue(key, out value))
return concurrent_dict.GetOrAdd(key, k => ValueFactory(k));
Run Code Online (Sandbox Code Playgroud)第三种情况显然不需要分配,第二种情况需要分配。
但是第一种情况(没有捕获的 lambda)是否完全不需要分配(至少在较新的 CLR 版本中)?另外,这是运行时的实现细节,还是标准指定的内容?
首先,CLR 不知道 lambda 是什么。这是一个 C# 概念。它被编译掉了。C# 语言为您提供了编写 lambda 的委托值。
C# 不保证委托实例(或底层方法)是否共享。事实上,我相信共享 lambda 委托的初始化是线程不安全且不安全的。因此,根据时间的不同,您可能只会看到一个或多个委托实例。
所以这是该语言的实现细节。
实际上,您可以依赖共享的表格 1 和 3。这对于性能来说很重要。如果不是这种情况,我认为它将被视为高优先级错误。