将简单的lambda表达式或局部函数分配给委托的性能 [英] Performance of assigning a simple lambda expression or a local function to a delegate

查看:73
本文介绍了将简单的lambda表达式或局部函数分配给委托的性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用非常简单的表达式作为键来创建具有 Enumerable.ToLookup< TSource,TKey>方法(IEnumerable< TSource> ;, Func< TSource,TKey>)) 我可以使用lambda表达式:

When using a very simple expression as key to create an ILookup with Enumerable.ToLookup<TSource, TKey> Method (IEnumerable<TSource>, Func<TSource, TKey>) I can use a lambda expression:

var lk = myItems.ToLookup((x) => x.Name);

或本地函数:

var lk = myItems.ToLookup(ByName);

string ByName(MyClass x)
{
     return x.Name;
}

我很好奇在这种简单情况下是否有所不同.

I'm curious if there is a difference in this simple case.

他的回答中,对本地函数与Lambda C#7.0 SO用户 svick 给出了一个很好的论据,即为什么通常使用本地函数比lambda更可取.

In his answer to Local function vs Lambda C# 7.0 SO user svick gives a good argument why –in general– local functions are preferable to lambdas.

重要的一点是性能上的差异:

An important point is the difference in performance:

创建lambda时,必须创建一个委托,在这种情况下,这是不必要的分配.本地函数实际上只是函数,不需要委托.

When creating a lambda, a delegate has to be created, which is an unnecessary allocation in this case. Local functions are really just functions, no delegates are necessary.

但是由于我们将其传递给 ToLookup(),所以仍然会创建一个委托.性能上还是有区别的吗?
我可以想象,编译器必须为myItems.ToLookup的每次调用创建一个新的委托lambda,而本地方法只需要一个委托实例即可.这是真的吗?

But since we pass it to ToLookup() a delegate is created anyway. Is there still a difference in performance?
I can imagine that the compiler has to create a fresh delegate lambda for each invocation of myItems.ToLookup, whereas there only needs to be a single delegate instance for the local method; is this true?

svick的表现的第二点差异

A second point of difference in performance in svick's answer is the capturing of variables and the creation of closures:

此外,局部函数在捕获局部变量时效率更高:lambda通常将变量捕获到类中,而局部函数可以使用结构体(使用ref传递),这又避免了分配.

Also, local functions are more efficient with capturing local variables: lambdas usually capture variables into a class, while local functions can use a struct (passed using ref), which again avoids an allocation.

但是,由于表达式不使用外部作用域中的变量,因此已声明通过里德·科普西 Eric Lippert >扩展来回答

However, since the expression does not use variables from the outer scope, there does not have to be a closure as stated by Reed Copsey and expanded by Eric Lippert in answer to Are Lambda expressions in C# closures?:

lambda可以使用闭包来实现,但它本身不一定是闭包.— 里德·科普西
[...]
可以视为对象的函数只是一个委托.使lambda成为闭包的原因是它捕获了其外部变量.— 埃里克·利珀特

这有点矛盾埃里克·利珀特本人就是他的将本地功能分配给代理人 Eric Lippert 解释了一个名为lambda的本地函数:

This is somewhat contradicted Eric Lippert himself is his answer to Assigning local functions to delegates Eric Lippert explains a local function as a named lambda:

本地函数基本上只是一个具有关联名称的lambda.

A local function is basically just a lambda with an associated name.

但这只是在较少的技术细节上,对于执行捕获外部作用域变量的lambda/局部函数的委托.

But this is at a level of lesser technical detail and for delegates of lambda's/local functions that do capture outer scope variables.

这个简单的表达式不是递归的,不是通用的,也不是迭代器.哪个看起来更好是一个意见问题.
那么,简单的不捕获,非递归,非泛型和非迭代器Lambda表达式与局部函数之间在性能(或其他方面)上是否存在差异?

This simple expression is not recursive, not generic, and not an iterator. And which looks better is a matter of opinion.
So, are there any differences in performance (or otherwise) between simple not capturing, non recursive, non generic, and non iterator lambda expressions and local functions?

推荐答案

使用当前版本的编译器(Roslyn 2.8.0),带有lambda的版本效率更高,因为它可以缓存委托.

With the current version of the compiler (Roslyn 2.8.0), the version with lambda is more efficient, because it caches the delegate.

综观代码的IL具有你的两个样品中的单独的方法,它很有效:

sealed class HelperClass
{
    public static readonly HelperClass Instance = new HelperClass();

    public static Func<MyClass, string> CachedDelegate;

    internal string LambdaByName(MyClass x)
    {
        return x.Name;
    }

    internal string LocalFunctionByName(MyClass x)
    {
        return x.Name;
    }
}

void Lambda(IEnumerable<MyClass> myItems)
{
    var lk = myItems.ToLookup(HelperClass.CachedDelegate ??
        (HelperClass.CachedDelegate =
            new Func<MyClass, string>(HelperClass.Instance.LambdaByName)));
}

void LocalFunction(IEnumerable<MyClass> myItems)
{
    var lk = myItems.ToLookup(
        new Func<MyClass, string>(HelperClass.Instance.LocalFunctionByName)));
}

请注意 Lambda 如何只分配一次委托,然后使用缓存的委托,而 LocalFunction 每次都分配委托.在这种特定情况下,这使 Lambda 更加有效.

Notice how Lambda allocates the delegate only once and uses a cached delegate afterwards, while LocalFunction allocates the delegate every time. This makes Lambda more efficient in this specific case.

尽管在GitHub上有关于将编译器更改为使用 LocalFunction 与 Lambda 一样有效.

Though there is a proposal on GitHub to change the compiler to make LocalFunction as efficient as Lambda.

这篇关于将简单的lambda表达式或局部函数分配给委托的性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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