我想知道在创建Background worker时是否通过使用匿名方法产生任何开销。
例如:
public void SomeMethod()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += (sender, e) =>
{
//large amount of code
}
worker.RunWorkerAsync();
}
上面的例子是否比在单独的方法中定义//large amount of code
更好或更差?
在线定义后台工作方法是否有任何开销,特别是如果经常调用SomeMethod()
?
从它们创建委托时,处理命名方法和匿名方法的方式略有不同。
匿名方法的委托被缓存,因此检查委托是否已存在于缓存中的开销很小。另一方面,如果您多次运行该方法,它将重用缓存的委托而不是创建新的委托。
命名方法的委托不会被缓存,因此每次都会创建。
除此之外没有区别。匿名方法将在编译时创建,并且像常规方法一样存在于代码中,仅具有只有编译器知道的名称。
首先,您可能不应该将大量代码放入匿名方法中。如果为这个方法创建一个单独的方法,甚至更好的方法,它将更具可读性。
对于生成的IL,如果lambda没有关闭任何变量,那么生成的IL代码与将代码放在普通命名方法中的情况相同(除了生成的方法具有不可说的名称)。
另一方面,如果关闭某个变量,编译器会创建一个闭包类来将该变量保存在字段中。并且字段访问比局部变量访问稍微贵一些。
总而言之,如果您关闭某些变量,则开销很小(包括需要进行垃圾回收的更多对象)。在大多数情况下,这并不重要,担心这将是过早的优化。但如果您认为它确实很重要,那么您应该对代码进行分析。
每当匿名方法(包括lambdas)关闭变量时,编译器就会创建一个类来为您保存这些变量。每当创建委托时,该类的新实例也是如此。这显然为运行时添加了额外的工作,但在大多数情况下通常可以忽略不计。
我前几天测试了这个(通过使用StopWatch类)。据我所知,在直接调用方法之间没有明显的性能差异......
SomeMethod();
......或通过匿名方法......
() => SomeMethod();
它主要影响可读性 - 一个地方的大量代码几乎从来都不好;-)
在性能方面,请参阅When is optimization premature?
这是反编译员所说的:
[CompilerGenerated]
private static DoWorkEventHandler CS$<>9__CachedAnonymousMethodDelegate1;
[CompilerGenerated]
private static void <SomeMethod1>b__0(object sender, DoWorkEventArgs e)
{
throw new NotImplementedException();
}
public void SomeMethod1()
{
BackgroundWorker worker = new BackgroundWorker();
BackgroundWorker backgroundWorker = worker;
backgroundWorker.DoWork += (object sender, DoWorkEventArgs e) => throw new NotImplementedException();
worker.RunWorkerAsync();
}
public void SomeMethod2()
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += worker_DoWork;
worker.RunWorkerAsync();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
throw new NotImplementedException();
}
编辑:
查看IL代码,第一次创建/分配方法委派时只需要很小的开销。