【问题标题】:Why is params 'less performant' than a regular array?为什么 params 的性能不如常规数组?
【发布时间】:2015-10-08 09:50:48
【问题描述】:

如果您现在在 IDE 中输入string.Format,您会看到有 4 种不同的重载:一个采用字符串和对象,另一个采用字符串和两个对象,然后一个采用三个对象,以及最后一个使用params。根据this answer 的说法,这是因为params 生成了'overhead',其他一些语言可能不支持。

我的问题是,为什么不能像这样调用方法:

void Foo()
{
    Bar(1, 2, 3);
}

void Bar(params int[] args)
{
    // use args...
}

在编译时本质上被转换为

void Foo()
{
    Bar(new[] { 1, 2, 3 });
}

void Bar(int[] args)
{
    // use args...
}

?然后它不会产生任何开销,除了创建数组(无论如何都是必要的),并且与其他语言完全兼容。

参数的数量在编译时就已经知道了,那么是什么阻止了 C# 编译器进行某种字符串替换并使第一个场景本质上是第二个场景的语法糖呢?为什么我们必须专门实现hidden language features 来支持可变参数?

【问题讨论】:

  • 数组创建是有关的开销链接答案。你没有摆脱这种开销。为重载提供一个、两个、三个参数确实使得在使用少于 4 个项目时调用数组分配是不必要的。
  • 内存开销不是这里唯一的问题 - 创建一个数组并用项目填充它会在您的方法中生成额外的 IL,这使得它不太可能被 JIT 内联。
  • 这只是一个猜测,但是如果编译器知道一个方法只需要 n 个参数而不是可变数量的参数,它可能能够更好地优化代码的性能,例如将变量存储在注册而不是创建一个数组。
  • @Matthew 和 MarcinJuraszek,如果它只是调用一个方法来执行您试图避免的操作,那么优化/内联代码有什么意义 - 创建一个数组,用 3 个元素填充它,然后传递它到params 过载?

标签: c# params variadic-functions


【解决方案1】:

标题做出了不正确的假设。

参数和非参数方法都采用数组;不同之处在于编译器会在进行params 方法调用时发出 IL 以隐式创建数组。 一个数组作为单个参数传递给这两个方法

这个can be seen in this .NET Fiddle(查看“整理 -> 查看 IL”)。

using System;

public class Program
{
    public static void Main()
    {
        var a1 = 1;
        var a2 = 2;
        var a3 = 3; 
        with_params(a1,a2,a3);
        no_params(new [] {a1,a2,a3});
    }

    public static void with_params(params int[] x) {}
    public static void no_params(int[] x) {}
}

两种情况中,IL 是相同的;一个新数组被创建,它被填充,并且该数组被提供给被调用的方法。

这个相同的 IL 生成有一个“例外”,因为编译器可以在以非参数形式使用时移出常量值数组并使用 'dup' 初始化,as seen here。但是,在这两种情况下,都提供了一个 new 数组作为参数。

【讨论】:

  • 谢谢,这是一个非常好的答案——但如果params int[]int[] 完全相同,那为什么some other languages 不能调用params int[]
  • @JamesKo 这将是特定语言本身的当前设计限制。在这些情况下,他们可以显式指定一个数组,或者可能调用其中一个 N 参数重载。
  • 是的,但是如果params 只是编译时的东西,那么他们不应该能够传入一个普通数组吗?
  • @JamesKo 是的,他们应该可以。但是,如果语言支持重载(并且它确实必须与 CLR/.NET 一起使用),即使不知道 params-behavior,它仍然可以对 1..4 参数使用“像 varargs 一样的工作”。 (我只使用支持参数的 C# 和 VB.NET,我不知道有一种语言不支持。)
猜你喜欢
  • 2020-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-27
  • 1970-01-01
  • 2011-08-24
  • 2015-12-29
  • 1970-01-01
相关资源
最近更新 更多