C# out 参数性能

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/527953/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 06:52:38  来源:igfitidea点击:

C# out parameter performance

c#parametersout

提问by Tamas Czinege

Do outparameters in C#have any performance implications I should know about? (Like exceptions)

C# 中的out参数是否有任何我应该知道的性能影响?(像例外)

I mean, is it a good idea to have a method with an outparameter in a loop that will run a couple of million times a second?

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

I know it's ugly but I am using it the same way as Int32.TryParseis using them - returning a boolto tell if some validation was successful and having an outparameter containing some additional data if it was successful.

我知道它很丑,但我使用它的方式与Int32.TryParse使用它们的方式相同- 返回 abool以判断某些验证是否成功,如果成功则返回out包含一些附加数据的参数。

采纳答案by Jon Skeet

I doubt that you'll find any significant performance penalty to using an outparameter. You've got to get information back to the caller somehow or other - outis just a different way of doing it. You may find there's somepenalty if you use the out parameter extensively within the method, as it may well mean an extra level of redirection for each access. However, I wouldn't expect it to be significant. As normal, write the most readable code and test whether performance is already good enoughbefore trying to optimise further.

我怀疑您会发现使用out参数会带来任何显着的性能损失。你必须以某种方式将信息返回给调用者 -out只是一种不同的方式。如果您在方法中广泛使用 out 参数,您可能会发现有一些惩罚,因为这很可能意味着每次访问都需要额外的重定向级别。但是,我不认为它会很重要。通常,在尝试进一步优化之前,编写可读性最强的代码并测试性能是否已经足够好

EDIT: The rest of this is an aside, effectively. It's only really relevant for large value types, which should usually be avoided anyway :)

编辑:其余部分是有效的。它只与大值类型真正相关,无论如何通常应该避免:)

I disagree with Konrad's assertion about "return values for all types > 32 bit are handled similar or identical to out arguments on the machine level anyway" though. Here's a little test app:

不过,我不同意 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();
    }
}

Results:

结果:

Using return value: 11316
Using out parameter: 7461

Basically by using an out parameter we're writing the data directly to the final destination, rather than writing it to the small method's stack frame and then copying it back into the Main method's stack frame.

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

Feel free to criticise the benchmark app though - I may have missed something!

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

回答by Konrad Rudolph

There are no performance implications. outis basically the same as any old argument passing, from a technical point of view. While it might sound plausible that huge amounds of data are copied (e.g. for large structs), this is actually the same as for return values.

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

In fact, return values for all types > 32 bit are handled similar to outarguments on the machine levelanyway.

事实上,所有类型 > 32 位的返回值的处理方式类似于机器级别的out参数。

Please note that the last statement doesn't suggest that returning a value == outparameter in .NET. Jon's benchmark shows that this is obviously (and regrettably) not the case. In fact, to make it identical, named return value optimizationis employed in C++ compilers. Something similar could potentially be done in future versions of the JIT to improve performance of returning large structures (however, since large structures are quite rare in .NET, this might be an unnecessary optimization).

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

However, (and with my very limited knowledge of x86 assembly), returning objects from function calls generally entails allocating sufficient space at the call site, pushing the address on the stack and filling it by copying the return value into it. This is basically the same that outdoes, only omitting an unnecessary temporary copy of the value since the target memory location can be accessed directly.

然而,(我对 x86 汇编的了解非常有限),从函数调用返回对象通常需要在调用站点分配足够的空间,将地址压入堆栈并通过将返回值复制到其中来填充它。这与out所做的基本相同,只是省略了不必要的值的临时副本,因为可以直接访问目标内存位置。

回答by Keith

The main reason for avoiding out parameters is code readability, rather than performance.

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

For value types there's no real difference anyway (they always copy) and for reference types it's basically the same as passing by ref.

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

Nine times out of ten you're better off creating your own dumb record class, rather than using an out parameter - this is simpler to read and understand when you return to the code later.

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

回答by thinkbeforecoding

Out parameters are passed by ref. So only a pointer passed on the stack.

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

If your value type is large, there is less copy, but then you have to dereference the pointer on each variable use.

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

回答by Giovanni Galbo

Using an out parameter does not hurt performance. An Out parameter is basically a reference parameter, so both the caller and the callee point to the same piece of memory.

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

回答by Marc Gravell

Not a performance issue, but something that came up earlier - you can't use them with variance in C# 4.0.

不是性能问题,而是早先出现的问题 -您不能在 C# 4.0 中使用它们

Personally, I tend to use outparameters a fair amount in my privatecode (i.e. inside a class, having a method that returns multiple values without using a separate type) - but I tend to avoid them on the public API, except for the bool Try{Something}(out result)pattern.

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