lambda函数比代理/匿名函数快吗? [英] Are lambda functions faster than delegates/anonymous functions?

查看:168
本文介绍了lambda函数比代理/匿名函数快吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我假设 lambda函数代表匿名函数同样的身体将具有相同的速度,但是,运行以下简单的程序:

I assumed lambda functions, delegates and anonymous functions with the same body would have the same "speed", however, running the following simple program:

static void Main(string[] args)
{
    List<int> items = new List<int>();

    Random random = new Random();

    for (int i = 0; i < 10000000; i++)
    {
        items.Add(random.Next());
    }

    Stopwatch watch;
    IEnumerable<int> result;

    Func<int, bool> @delegate = delegate(int i)
    {
        return i < 500;
    };
    watch = Stopwatch.StartNew();
    result = items.Where(@delegate);
    watch.Stop();
    Console.WriteLine("Delegate: {0}", watch.Elapsed.TotalMilliseconds);

    Func<int, bool> lambda = i => i < 500;
    watch = Stopwatch.StartNew();
    result = items.Where(lambda);
    watch.Stop();
    Console.WriteLine("Lambda: {0}", watch.Elapsed.TotalMilliseconds);

    watch = Stopwatch.StartNew();
    result = items.Where(i => i < 500);
    watch.Stop();
    Console.WriteLine("Inline: {0}", watch.Elapsed.TotalMilliseconds);

    Console.ReadLine();
}

我得到:

代理:4.2948 ms

Delegate: 4.2948 ms

Lambda:0.0019 ms

Lambda: 0.0019 ms

匿名:0.0034 ms

Anonymous: 0.0034 ms

尽管可以忽略不计,为什么这三种 - 显然是相同的方法运行在不同的速度?发生什么事情?

Although negligible, why are these three - apparently identical - methods running at different speeds? What's happening under the hood?

更新:

根据意见建议,以下强制 Where 通过调用 ToList()在上面。此外,还添加了一个循环来提供更多的运行数据:

As suggested by the comments, the following "forces" the Where by calling ToList() on it. In addition, a loop is added to offer more run data:

while (true) 
{
    List<int> items = new List<int>();

    Random random = new Random();

    for (int i = 0; i < 10000000; i++)
    {
        items.Add(random.Next());
    }

    Stopwatch watch;
    IEnumerable<int> result;

    Func<int, bool> @delegate = delegate(int i)
    {
        return i < 500;
    };
    watch = Stopwatch.StartNew();
    result = items.Where(@delegate).ToList();
    watch.Stop();
    Console.WriteLine("Delegate: {0}", watch.Elapsed.TotalMilliseconds);

    Func<int, bool> lambda = i => i < 500;
    watch = Stopwatch.StartNew();
    result = items.Where(lambda).ToList();
    watch.Stop();
    Console.WriteLine("Lambda: {0}", watch.Elapsed.TotalMilliseconds);

    watch = Stopwatch.StartNew();
    result = items.Where(i => i < 500).ToList();
    watch.Stop();
    Console.WriteLine("Inline: {0}", watch.Elapsed.TotalMilliseconds);
    Console.WriteLine(new string('-', 12));

}

上述代码为每个功能产生〜120 ms。

The above code results in ~120 ms for each function.

推荐答案

一个lambda表达式一个匿名函数。 匿名函数是指lambda表达式或匿名方法(这是您在代码中称为代理的 )。

A lambda expression is an anonymous function. "Anonymous function" refers to either a lambda expression or an anonymous method (which is what you've called a "delegate" in your code).

所有三个操作都使用代理。第二个和第三个都使用lambda表达式。所有这三个将以相同的方式执行,具有相同的性能特征。

All three operations are using delegates. The second and third are both using lambda expressions. All three will execute in the same way, with the same performance characteristics.

请注意,可以在性能上有所不同: p>

Note that there can be a difference in performance between:

Func<int, int> func = x => ...;
for (int i = 0; i < 10000; i++) {
    CallFunc(func);
}

for (int i = 0; i < 10000; i++) {
    CallFunc(x => ...) // Same lambda as before
}

这取决于编译器是否能够缓存由lambda表达式创建的委托。这将取决于它是否捕获变量等。

It depends on whether the compiler is able to cache the delegate created by the lambda expression. That will in turn depend on whether it captures variables etc.

例如,考虑这个代码:

using System;
using System.Diagnostics;

class Test
{
    const int Iterations = 1000000000;

    static void Main()
    {
        AllocateOnce();
        AllocateInLoop();
    }

    static void AllocateOnce()
    {
        int x = 10;

        Stopwatch sw = Stopwatch.StartNew();
        int sum = 0;
        Func<int, int> allocateOnce = y => y + x;
        for (int i = 0; i < Iterations; i++)
        {
            sum += Apply(i, allocateOnce);
        }
        sw.Stop();
        Console.WriteLine("Allocated once: {0}ms", sw.ElapsedMilliseconds);
    }

    static void AllocateInLoop()
    {
        int x = 10;

        Stopwatch sw = Stopwatch.StartNew();
        int sum = 0;
        for (int i = 0; i < Iterations; i++)
        {
            sum += Apply(i, y => y + x);
        }
        sw.Stop();
        Console.WriteLine("Allocated in loop: {0}ms", sw.ElapsedMilliseconds);
    }

    static int Apply(int loopCounter, Func<int, int> func)
    {
        return func(loopCounter);
    }
}

编译器很聪明,但仍然有差异。使用Reflector,我们可以看到 AllocateInLoop 被有效地编译为:

The compiler is smart, but there's still a difference. Using Reflector, we can see that AllocateInLoop is effectively compiled to:

private static void AllocateInLoop()
{
    Func<int, int> func = null;
    int x = 10;
    Stopwatch stopwatch = Stopwatch.StartNew();
    int sum = 0;
    for (int i = 0; i < Iterations; i++)
    {
        if (func == null)
        {
            func = y => y + x;
        }
        sum += Apply(i, func);
    }
    stopwatch.Stop();
    Console.WriteLine("Allocated in loop: {0}ms", stopwatch.ElapsedMilliseconds);
}

所以仍然只创建一个委托实例,但是在循环 - 基本上是每次迭代的额外的无效性测试。

So still only a single delegate instance is created, but there's extra logic within the loop - an extra nullity test on each iteration, basically.

在我的机器上,性能差异在15%左右。

On my machine that makes about a 15% difference in performance.

这篇关于lambda函数比代理/匿名函数快吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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