.net - 为什么从表达式动态生成的委托(delegate)比硬编码的 lambda 慢?

标签 .net performance delegates lambda expression-trees

我希望从表达式树生成的委托(delegate)能够实现与硬编码、静态、等效匿名方法大致相同的性能。但是,动态生成的委托(delegate)似乎要慢得多……

这里有一个简单的测试程序来说明这个案例。它只访问对象的 3 个属性 1000000 次:

static void Main()
{
    var foo = new Foo { A = 42, B = "Hello world", C = new DateTime(1970, 1, 1) };

    Func<Foo, int> getA;
    Func<Foo, string> getB;
    Func<Foo, DateTime> getC;

    // Using hard-coded lambdas
    getA = f => f.A;
    getB = f => f.B;
    getC = f => f.C;
    Console.WriteLine("Hard-coded: {0}", Test(foo, getA, getB, getC));

    // Using dynamically generated delegates
    ParameterExpression prm = Expression.Parameter(typeof(Foo), "foo");
    getA = Expression.Lambda<Func<Foo, int>>(Expression.Property(prm, "A"), prm).Compile();
    getB = Expression.Lambda<Func<Foo, string>>(Expression.Property(prm, "B"), prm).Compile();
    getC = Expression.Lambda<Func<Foo, DateTime>>(Expression.Property(prm, "C"), prm).Compile();
    Console.WriteLine("Generated:  {0}", Test(foo, getA, getB, getC));
}

const int N = 1000000;

static TimeSpan Test(Foo foo, Func<Foo, int> getA, Func<Foo, string> getB, Func<Foo, DateTime> getC)
{
    var sw = Stopwatch.StartNew();
    for (int i = 0; i < N; i++)
    {
        getA(foo);
        getB(foo);
        getC(foo);
    }
    sw.Stop();
    return sw.Elapsed;
}

public class Foo
{
    public int A { get; set; }
    public string B { get; set; }
    public DateTime C { get; set; }
}

我一直得到的结果表明,硬编码的 lambda 的速度大约快 6 倍:
Hard-coded: 00:00:00.0115959
Generated:  00:00:00.0735896

Hard-coded: 00:00:00.0113993
Generated:  00:00:00.0648543

Hard-coded: 00:00:00.0115280
Generated:  00:00:00.0611804

谁能解释这些结果?这是由于编译器优化吗?还是 JIT 优化?

感谢您的洞察力

编辑:我正在使用 LINQPad 运行我的测试,它在启用优化的情况下进行编译。当我在禁用优化的 VS 中运行相同的测试时,两种情况下的结果大致相同。所以看起来编译器只是在硬编码的 lambda 中内联属性访问......

额外的问题:有没有办法优化从表达式树生成的代码?

最佳答案

只是一个猜测,但我认为优化器看到 Lambda 表达式是简单的 getter 并将它们转换为直接访问或类似的。生成的表达式无法优化,因此它们会导致代码变慢。

它应该在编译时发生,因此您应该在禁用优化的情况下尝试它并再次检查结果。

关于.net - 为什么从表达式动态生成的委托(delegate)比硬编码的 lambda 慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3392388/

相关文章:

c# - 如何从单独的程序集中加载 WPF 应用程序资源 "via Code"(不是 "via XAML")

.net - 是否存在可以接受 InternalsVisibleTo 的非单元测试场景

excel - 为细胞着色的另一种更快的方法

c# - .NET 中具有深度继承的类的内存分配

iphone - UITableViewController 不调用委托(delegate)方法

c# - 我如何动态创建类的对象?

c# - 如何使用配置转换删除 ConnectionString

Java:成对对象的高效集合概念

c# - 使用 delegate/BeginInvoke 在 C# 中将调用者与被调用者解耦

macos - 使用 Swift "why"做一些委托(delegate)函数需要覆盖 func