为什么Func键<> Func键<从表达式来创建>>比Func键&LT慢;>直接声明? [英] Why is Func<> created from Expression<Func<>> slower than Func<> declared directly?

查看:124
本文介绍了为什么Func键<> Func键<从表达式来创建>>比Func键&LT慢;>直接声明?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么一个 Func键<>通过.Compile ; Func键<>>从表达式来创建 ()比只用一个 Func键<相当慢;> 直接宣布

Why is a Func<> created from an Expression<Func<>> via .Compile() considerably slower than just using a Func<> declared directly ?

我刚刚从使用变 Func键< IInterface,对象> 直接宣布一个从表达式来创建的; Func键< IInterface,对象>> 在应用我的工作和我注意到,业绩下降。

I just changed from using a Func<IInterface, object> declared directly to one created from an Expression<Func<IInterface, object>> in an app i am working on and i noticed that the performance went down.

我刚刚做了一个小测试,而 Func键<> 从表达式创建以几乎翻番的时间 Func键<> 直接宣布

I have just done a little test, and the Func<> created from an Expression takes "almost" double the time of an Func<> declared directly.

在我的机器上直接 Func键<> 花费约7.5秒,表达式来; Func键<>> 需要12.6秒。

On my machine the Direct Func<> takes about 7.5 seconds and the Expression<Func<>> takes about 12.6 seconds.

下面是我使用的测试代码(运行.NET 4.0)

Here is the test code I used (running Net 4.0)

// Direct
Func<int, Foo> test1 = x => new Foo(x * 2);

int counter1 = 0;

Stopwatch s1 = new Stopwatch();
s1.Start();
for (int i = 0; i < 300000000; i++)
{
 counter1 += test1(i).Value;
}
s1.Stop();
var result1 = s1.Elapsed;



// Expression . Compile()
Expression<Func<int, Foo>> expression = x => new Foo(x * 2);
Func<int, Foo> test2 = expression.Compile();

int counter2 = 0;

Stopwatch s2 = new Stopwatch();
s2.Start();
for (int i = 0; i < 300000000; i++)
{
 counter2 += test2(i).Value;
}
s2.Stop();
var result2 = s2.Elapsed;



public class Foo
{
 public Foo(int i)
 {
  Value = i;
 }
 public int Value { get; set; }
}



我怎样才能获得的性能回来?



有什么我可以做的就是 Func键<> Func键<>> 表达式来创建; 执行类似一是直接宣布

How can i get the performance back ?

Is there anything i can do to get the Func<> created from the Expression<Func<>> to perform like one declared directly ?

推荐答案

,调用的开销?动态委派导致您的放缓。在我的电脑的开销大约与我在3GHz的CPU为12ns。要解决这个问题的方法是从一个编译的程序集加载方法,像这样的:

As others have mentioned, the overhead of calling a dynamic delegate is causing your slowdown. On my computer that overhead is about 12ns with my CPU at 3GHz. The way to get around that is to load the method from a compiled assembly, like this:

var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(
             new AssemblyName("assembly"), AssemblyBuilderAccess.Run);
var mod = ab.DefineDynamicModule("module");
var tb = mod.DefineType("type", TypeAttributes.Public);
var mb = tb.DefineMethod(
             "test3", MethodAttributes.Public | MethodAttributes.Static);
expression.CompileToMethod(mb);
var t = tb.CreateType();
var test3 = (Func<int, Foo>)Delegate.CreateDelegate(
                typeof(Func<int, Foo>), t.GetMethod("test3"));

int counter3 = 0;
Stopwatch s3 = new Stopwatch();
s3.Start();
for (int i = 0; i < 300000000; i++)
{
    counter3 += test3(i).Value;
}
s3.Stop();
var result3 = s3.Elapsed;

当我添加了上面的代码, result3 永远只是比 RESULT1 的第二高分数,约一1ns的开销。

When I add the above code, result3 is always just a fraction of a second higher than result1, for about a 1ns overhead.

那么,为什么甚至不屑与编译的lambda(测试2 )的时候可以有更快的委托( TEST3 )?因为在创建动态组装是一般更开销,并且只为您节省10-20ns在每次调用。

So why even bother with a compiled lambda (test2) when you can have a faster delegate (test3)? Because creating the dynamic assembly is much more overhead in general, and only saves you 10-20ns on each invocation.

这篇关于为什么Func键&LT;&GT; Func键&LT;从表达式来创建&GT;&GT;比Func键&LT慢;&GT;直接声明?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆