C#输出参数性能

时间:2009-02-09 12:31:28

标签: c# parameters out

C#中的 out 参数是否具有我应该了解的性能影响? (例外情况)

我的意思是,在循环中使用out参数的方法是一个好主意,每秒运行几百万次?

我知道它很难看,但我使用的方式与Int32.TryParse使用它们的方式相同 - 返回bool来判断某些验证是否成功并且out参数包含一些如果成功则需要额外的数据。

6 个答案:

答案 0 :(得分:33)

我怀疑您使用out参数会发现任何显着的性能损失。你必须以某种方式或其他方式将信息传回呼叫者 - out只是一种不同的方式。如果在方法中广泛使用out参数,您可能会发现某些惩罚,因为它可能意味着每次访问都需要额外的重定向级别。但是,我不认为它会很重要。正常情况下,在尝试进一步优化之前,请编写最易读的代码和test whether performance is already good enough

编辑:其余部分是有效的。它只适用于大值类型,通常应该避免使用:)

我不同意Konrad关于“所有类型的返回值> 32位的处理方式与机器级别的out参数相似或相同”的断言,不过。这是一个小测试应用程序:

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;

struct BigStruct
{
    public Guid guid1, guid2, guid3, guid4;
    public decimal dec1, dec2, dec3, dec4;
}

class Test
{
    const int Iterations = 100000000;

    static void Main()
    {
        decimal total = 0m;
        // JIT first
        ReturnValue();
        BigStruct tmp;
        OutParameter(out tmp);

        Stopwatch sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            BigStruct bs = ReturnValue();
            total += bs.dec1;
        }
        sw.Stop();
        Console.WriteLine("Using return value: {0}",
                          sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            BigStruct bs;
            OutParameter(out bs);
            total += bs.dec1;
        }
        Console.WriteLine("Using out parameter: {0}",
                          sw.ElapsedMilliseconds);
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    public static BigStruct ReturnValue()
    {
        return new BigStruct();
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    public static void OutParameter(out BigStruct x)
    {
        x = new BigStruct();
    }
}

结果:

Using return value: 11316
Using out parameter: 7461

基本上通过使用out参数,我们将数据直接写入最终目标,而不是将其写入small方法的堆栈帧,然后将其复制回Main方法的堆栈帧。

随意批评基准应用程序 - 我可能错过了一些东西!

答案 1 :(得分:5)

没有性能影响。从技术角度来看,out基本上与任何旧参数相同。虽然复制大量数据可能听起来似乎有道理(例如对于大型结构),但这实际上与返回值相同。

实际上,所有类型的返回值&gt;无论如何,32位处理类似于机器级别上的out参数。

请注意,最后一条语句并不建议在.NET中返回值== out参数。 Jon的基准测试显示,这显然(并且令人遗憾)并非如此。事实上,为了使它相同,{C ++编译器中使用named return value optimization。在JIT的未来版本中可能会做类似的事情,以提高返回大型结构的性能(但是,由于.NET中的大型结构非常少见,这可能是一种不必要的优化)。

然而,(由于我对x86程序集的知识非常有限),从函数调用返回对象通常需要在调用站点分配足够的空间,推送堆栈上的地址并通过复制填充它返回值。这与out基本相同,只是省略了不必要的临时值,因为可以直接访问目标内存位置。

答案 2 :(得分:5)

不是性能问题,而是早先出现的问题 - you can't use them with variance in C# 4.0

就个人而言,我倾向于在我的私有代码中使用out个参数(即在一个类中,有一个方法可以返回多个值而不使用单独的类型) - 但是除了bool Try{Something}(out result)模式之外,我倾向于在公共API上避免使用它们。

答案 3 :(得分:1)

避免输出参数的主要原因是代码可读性,而不是性能。

对于值类型,无论如何都没有真正的区别(它们总是复制),对于引用类型,它与通过ref的基本相同。

十分之九,你最好创建自己的哑记录类,而不是使用out参数 - 当你稍后返回代码时,这更易于阅读和理解。

答案 4 :(得分:1)

输出参数由ref传递。所以只有一个指针在堆栈上传递。

如果您的值类型很大,则副本较少,但是您必须取消引用每个变量使用的指针。

答案 5 :(得分:0)

使用out参数不会影响性能。 Out参数基本上是一个引用参数,因此调用者和被调用者都指向同一块内存。

相关问题