C#中的 out 参数是否具有我应该了解的性能影响? (例外情况)
我的意思是,在循环中使用out
参数的方法是一个好主意,每秒运行几百万次?
我知道它很难看,但我使用的方式与Int32.TryParse
使用它们的方式相同 - 返回bool
来判断某些验证是否成功并且out
参数包含一些如果成功则需要额外的数据。
答案 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参数基本上是一个引用参数,因此调用者和被调用者都指向同一块内存。