Filip Ekberg在“ .NET异步编程入门”的“异步编程深度学习/使用附加和分离的任务”一章中,他说通过使用service异步匿名方法内部的值,它引入了闭包和不必要的分配:
接下来,他说,这是更好地传递services作为参数的的动作代表StartNew的方法,其通过避免关闭避免了不必要的分配:
我的问题是:
作者说通过传递servicesas参数可以节省多少分配?
为了便于调查,我举了一个简单得多的示例,并将其放在sharplab.io:
没有传递参数:
using System;
public class C {
public void M() {
var i = 1;
Func<int> f = () => i + 1;
f();
}
}
Run Code Online (Sandbox Code Playgroud)
编译为:
public class C
{
[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
public int i;
internal int <M>b__0()
{
return i + 1;
}
}
public void M()
{
<>c__DisplayClass0_0 <>c__DisplayClass0_ = new <>c__DisplayClass0_0();
<>c__DisplayClass0_.i = 1;
new Func<int>(<>c__DisplayClass0_.<M>b__0)();
}
}
Run Code Online (Sandbox Code Playgroud)
有两种分配,一种分配给生成的类,一种分配给Func<int>委托。
传递参数:
using System;
public class C {
public void M() {
var i = 1;
Func<int, int> f = (x) => x + 1;
f(i);
}
}
Run Code Online (Sandbox Code Playgroud)
编译为:
public class C
{
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static Func<int, int> <>9__0_0;
internal int <M>b__0_0(int x)
{
return x + 1;
}
}
public void M()
{
int arg = 1;
(<>c.<>9__0_0 ?? (<>c.<>9__0_0 = new Func<int, int>(<>c.<>9.<M>b__0_0)))(arg);
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,仍然有两种分配,一种分配给生成的类(请注意,该类中有一个静态字段创建该类的实例),另一种分配给Func<int>委托。
据我所知,在两种情况下,编译器都会生成一个类,并且有两个分配。
我可以看到的唯一区别是,在第一种情况下,生成的类具有一个成员:
[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
public int i;
Run Code Online (Sandbox Code Playgroud)
这确实增加了分配大小,因为生成的类比第二种情况占用更多的内存。
我是否理解正确,这是作者所指的吗?
区别在于缓存。
在您的原始代码中,每次调用时都会创建一个新的委托实例M()。在“聪明”版本中,每次仅创建一个实例并将其存储在静态变量中。
因此,如果只调用M()一次,就会分配相同数量的对象。如果调用M()一百万次,第一个代码分配的对象将比第二个代码分配的对象多得多。
这段代码:
(<>c.<>9__0_0 ?? (<>c.<>9__0_0 = new Func<int, int>(<>c.<>9.<M>b__0_0)))(arg);
Run Code Online (Sandbox Code Playgroud)
...应该有效地解读为:
if (cachedDelegate == null)
{
cachedDelegate = new Func<int, int>(GeneratedClass.CachedInstance.Method);
}
cachedDelegate.Invoke(arg);
Run Code Online (Sandbox Code Playgroud)
的实例<>c也会被缓存(上面称为GeneratedClass.CachedInstance) - 仅创建该实例的单个实例。(尽管这在这里不太重要,因为它只需要在创建委托时创建......我不确定在什么情况下编译器优化特别有用。)
| 归档时间: |
|
| 查看次数: |
218 次 |
| 最近记录: |