多个 return 变量 - 哪个具有最佳性能(输出、元组、class)?
Multiple return variables - which has best performance (out, tuple, class)?
实现returns多次双打的方法有多种:
通过out
参数:
class MyClass
{
static double Add3(double x, out double xp1, out double xp2)
{
xp1 = x + 1.0;
xp2 = x + 2.0;
return x + 3.0;
}
}
通过元组:
class MyClass
{
static Tuple<double, double, double> Add3(double x)
{
Tuple<double, double, double> ret = new Tuple<double, double, double>();
ret.Item1 = x + 1.0;
ret.Item2 = x + 2.0;
ret.Item3 = x + 3.0;
return ret;
}
通过 class 收集结果:
class MyClass
{
class Result
{
double xp1;
double xp2;
double xp3;
}
static Result Add3(double x)
{
Result ret = new Result
{
xp1 = x + 1.0;
xp2 = x + 2.0;
xp3 = x + 3.0;
}
return ret;
}
}
我对 this question 的评论的印象是,人们普遍认为带有额外 class 的方法是最佳实践。但是,我想知道是否有关于三种变体对 运行 时间性能的影响的经验法则。
与 out
参数相比,Tuple
或 class 的构造函数是否需要额外的时间?
特别是,在实际使用结果双打中只有一个的情况下,带有 out
参数的变体是否具有任何性能优势,例如在以下代码段中?
double zPlus3 = MyClass.Add3(z, out _, out _)
通过 Tuple<T1,T2,T3>
or a custom class with 3 properties, is equivalent performance-wise. Tuples are more readily available (you don't have to code them) while custom classes are more convenient to use, but both approaches involve the instantiation of a reference-type, that has to be heap-allocated and later garbage collected. If you use these types just for accessing their properties once, then you are getting no added value to compensate for the heap-allocation/garbage collection overhead. Using out
parameters is superior performance-wise in this case. There is a forth solution though, that combines the advantages of all these approaches: value tuples 返回多个值(在 C# 7.0 及更高版本中可用)。
static (double, double, double) Add3(double x)
{
return (x + 1.0, x + 2.0, x + 3.0);
}
用法示例,演示 tuple deconstruction:
(double xp1, double xp2, double xp3) = Add3(13);
...或等效地使用类型推断:
var (xp1, xp2, xp3) = Add3(13);
优点:
- A
ValueTuple<T1,T2,T3>
与 Tuple<T1,T2,T3>
一样容易获得。
- 语言支持 changing the field names 的
ValueTuple<T1,T2,T3>
比 Item1
、Item2
和 Item3
更有意义的东西,使它们(几乎)同样方便自定义 class.
- 一个
ValueTuple<T1,T2,T3>
入栈,和out
参数一样。不涉及堆分配和垃圾收集。
为了向这个问题添加一些确凿的事实,here 是一个比较这些备选方案性能的基准项目。
令人惊讶的是,.NET 对 ValueTuple 和 KeyValuePair 进行了大量优化,
与调试相比,发布模式下的执行时间减少了 34 倍!
在发布模式下,所有实现都具有相似的速度,
除了返回 Tuple{int,int}
由于大量垃圾收集,速度慢了 10 倍。
在调试模式下,只有使用输出参数的方法是快速的。
从调试到发布构建的相对速度因子在最后一列'*'
中给出
Method
Release
Debug
*
Return Tuple
510.84 ms
1,515.2 ms
3
Return KeyValuePair
44.56 ms
1,527.1 ms
34
Return ValueTuple
51.28 ms
1,418.6 ms
28
Return NullableValue
48.41 ms
1,527.0 ms
29
2 out Parameters
43.83 ms
560.4 ms
14
1 out Parameter
48.41 ms
586.5 ms
13
Return Single Value
49.72 ms
523.8 ms
11
实现returns多次双打的方法有多种:
通过out
参数:
class MyClass
{
static double Add3(double x, out double xp1, out double xp2)
{
xp1 = x + 1.0;
xp2 = x + 2.0;
return x + 3.0;
}
}
通过元组:
class MyClass
{
static Tuple<double, double, double> Add3(double x)
{
Tuple<double, double, double> ret = new Tuple<double, double, double>();
ret.Item1 = x + 1.0;
ret.Item2 = x + 2.0;
ret.Item3 = x + 3.0;
return ret;
}
通过 class 收集结果:
class MyClass
{
class Result
{
double xp1;
double xp2;
double xp3;
}
static Result Add3(double x)
{
Result ret = new Result
{
xp1 = x + 1.0;
xp2 = x + 2.0;
xp3 = x + 3.0;
}
return ret;
}
}
我对 this question 的评论的印象是,人们普遍认为带有额外 class 的方法是最佳实践。但是,我想知道是否有关于三种变体对 运行 时间性能的影响的经验法则。
与 out
参数相比,Tuple
或 class 的构造函数是否需要额外的时间?
特别是,在实际使用结果双打中只有一个的情况下,带有 out
参数的变体是否具有任何性能优势,例如在以下代码段中?
double zPlus3 = MyClass.Add3(z, out _, out _)
通过 Tuple<T1,T2,T3>
or a custom class with 3 properties, is equivalent performance-wise. Tuples are more readily available (you don't have to code them) while custom classes are more convenient to use, but both approaches involve the instantiation of a reference-type, that has to be heap-allocated and later garbage collected. If you use these types just for accessing their properties once, then you are getting no added value to compensate for the heap-allocation/garbage collection overhead. Using out
parameters is superior performance-wise in this case. There is a forth solution though, that combines the advantages of all these approaches: value tuples 返回多个值(在 C# 7.0 及更高版本中可用)。
static (double, double, double) Add3(double x)
{
return (x + 1.0, x + 2.0, x + 3.0);
}
用法示例,演示 tuple deconstruction:
(double xp1, double xp2, double xp3) = Add3(13);
...或等效地使用类型推断:
var (xp1, xp2, xp3) = Add3(13);
优点:
- A
ValueTuple<T1,T2,T3>
与Tuple<T1,T2,T3>
一样容易获得。 - 语言支持 changing the field names 的
ValueTuple<T1,T2,T3>
比Item1
、Item2
和Item3
更有意义的东西,使它们(几乎)同样方便自定义 class. - 一个
ValueTuple<T1,T2,T3>
入栈,和out
参数一样。不涉及堆分配和垃圾收集。
为了向这个问题添加一些确凿的事实,here 是一个比较这些备选方案性能的基准项目。
令人惊讶的是,.NET 对 ValueTuple 和 KeyValuePair 进行了大量优化, 与调试相比,发布模式下的执行时间减少了 34 倍!
在发布模式下,所有实现都具有相似的速度, 除了返回 Tuple{int,int} 由于大量垃圾收集,速度慢了 10 倍。
在调试模式下,只有使用输出参数的方法是快速的。 从调试到发布构建的相对速度因子在最后一列'*'
中给出Method | Release | Debug | * |
---|---|---|---|
Return Tuple | 510.84 ms | 1,515.2 ms | 3 |
Return KeyValuePair | 44.56 ms | 1,527.1 ms | 34 |
Return ValueTuple | 51.28 ms | 1,418.6 ms | 28 |
Return NullableValue | 48.41 ms | 1,527.0 ms | 29 |
2 out Parameters | 43.83 ms | 560.4 ms | 14 |
1 out Parameter | 48.41 ms | 586.5 ms | 13 |
Return Single Value | 49.72 ms | 523.8 ms | 11 |