提问人:mike 提问时间:10/13/2022 最后编辑:trincotmike 更新时间:10/17/2022 访问量:60
为什么不仅在实际需要时创建闭包帮助程序实例 (DisplayClass)?
Why aren't closure helper instances (DisplayClass) only created when actually needed?
问:
我有一个关于关闭和堆分配的问题。请考虑以下代码:
//ORIGINAL CODE, VERSION 1
public class Program
{
private ConcurrentDictionary<object, object> _coll = new ConcurrentDictionary<object, object>();
public object Test(String x){
if(x == "abort") return null;
return _coll.GetOrAdd(x, (k)=> TestCallback());
}
public static object TestCallback() => null;
}
在回调函数中使用。而且,根据 https://sharplab.io,这被降低到(缩写):Test
static
//LOWERED CODE, VERSION 1
public class Program
{
private sealed class <>c
{
public static readonly <>c <>9 = new <>c(); // <== HELPER1 CREATION
public static Func<object, object> <>9__1_0;
internal object <Test>b__1_0(object k)
{
return TestCallback();
}
}
private ConcurrentDictionary<object, object> _coll = new ConcurrentDictionary<object, object>();
public object Test(string x)
{
if (x == "abort")
{
return null;
}
return _coll.GetOrAdd(x, <>c.<>9__1_0 ?? (<>c.<>9__1_0 = new Func<object, object>(<>c.<>9.<Test>b__1_0))); // <== HELPER2 CREATION
}
public static object TestCallback() //==> STATIC METHOD
{
return null;
}
}
因此,编译器会创建一些帮助程序对象,但只执行一次(帮助程序是静态的)。
现在,如果我从...中删除:static
TestCallback
//ORIGINAL CODE, VERSION 1
public class Program
{
private ConcurrentDictionary<object, object> _coll = new ConcurrentDictionary<object, object>();
public object Test(String x){
if(x == "abort") return null;
return _coll.GetOrAdd(x, (k)=> TestCallback());
}
public object TestCallback() => null; //==> INSTANCE METHOD
}
...降低的代码更改为:
//LOWERED CODE, VERSION 2
public class Program
{
private ConcurrentDictionary<object, object> _coll = new ConcurrentDictionary<object, object>();
public object Test(string x)
{
if (x == "abort")
{
return null;
}
return _coll.GetOrAdd(x, new Func<object, object>(<Test>b__1_0)); // <== HELPER1 CREATION
}
public object TestCallback()
{
return null;
}
private object <Test>b__1_0(object k)
{
return TestCallback();
}
}
现在看来,如果 a 不为 true(即 实际上称为)。new Func
x == "abort"
_coll.GetOrAdd
最后,如果我更改为包含一个参数...:Test
callback
//ORIGINAL CODE, VERSION 3
public class Program
{
private ConcurrentDictionary<object, object> _coll = new ConcurrentDictionary<object, object>();
public object Test(String x, Func<object> callback){
if(x == "abort") return null;
return _coll.GetOrAdd(x, (k)=> callback());
}
}
...降低的代码更改为:
//LOWERED CODE, VERSION 3
public class Program
{
private sealed class <>c__DisplayClass1_0
{
public Func<object> callback;
internal object <Test>b__0(object k)
{
return callback();
}
}
private ConcurrentDictionary<object, object> _coll = new ConcurrentDictionary<object, object>();
public object Test(string x, Func<object> callback)
{
<>c__DisplayClass1_0 <>c__DisplayClass1_ = new <>c__DisplayClass1_0(); // <== HELPER1 CREATION
<>c__DisplayClass1_.callback = callback;
if (x == "abort")
{
return null;
}
return _coll.GetOrAdd(x, new Func<object, object>(<>c__DisplayClass1_.<Test>b__0)); // <== HELPER2 CREATION
}
}
在这里,它看起来好像在每次调用时都会创建一个 ,而不管 .new <>c__DisplayClass1_0
x == "abort"
总结一下:
- 版本 1:一次创建 2 个助手。
- 版本 2:每当实际调用时,都会创建 1 个帮助程序。
_cao..GetOrAdd
- 版本3:在每次调用时创建2个助手。
这是正确的吗?如果降低的代码是正确的(并且是实际编译器使用的代码),为什么在相关调用之前没有立即创建?new <>c__DisplayClass1_0
这样就可以防止不必要的分配。最终,我想知道,这是否是实际的改进:
public IMetadata GetOrDefineMetadata(object key, Func<IMetadata> createCallback)
{
if (_coll.TryGetValue(key, out var result)) return result; //THIS LINE WAS INSERTED AS AN IMPROVEMENT
return _coll.GetOrAdd(key, (k) => createCallback()); // ==> WILL THIS STILL CAUSE ALLOCATIONS ON EVERY CALL?
}
答:
1赞
Manuel
10/17/2022
#1
这看起来像是编译器优化的机会。
我把电话转到了_coll。GetOrAdd 到静态方法。在降低的代码中,这会进一步降低分配。
public class Program
{
private ConcurrentDictionary<object, object> _coll = new ConcurrentDictionary<object, object>();
public object Test(String x, Func<object> callback){
if(x == "abort") return null;
return GetOrAdd(x, _coll, callback);
}
private static object GetOrAdd(string x, ConcurrentDictionary<object, object> dict, Func<object> callback)
{
return dict.GetOrAdd(x, (_)=> callback());
}
}
降低版本:
public class Program
{
[CompilerGenerated]
private sealed class <>c__DisplayClass2_0
{
public Func<object> callback;
internal object <GetOrAdd>b__0(object _)
{
return callback();
}
}
private ConcurrentDictionary<object, object> _coll = new ConcurrentDictionary<object, object>();
public object Test(string x, Func<object> callback)
{
if (x == "abort")
{
return null;
}
return GetOrAdd(x, _coll, callback);
}
private static object GetOrAdd(string x, ConcurrentDictionary<object, object> dict, Func<object> callback)
{
<>c__DisplayClass2_0 <>c__DisplayClass2_ = new <>c__DisplayClass2_0();
<>c__DisplayClass2_.callback = callback;
return dict.GetOrAdd(x, new Func<object, object>(<>c__DisplayClass2_.<GetOrAdd>b__0));
}
}
评论