为何Avg()性能优于Sum()?基于BenchmarkDotnet的测试疑问
性能测试疑问:Avg() 比 Sum() 更快的原因
测试环境
- C# 11.0
- .NET 7.0
- BenchmarkDotNet 版本:0.13.5
测试代码
ReadOnlyMemory<float> readOnlyFloats; ReadOnlyMemory<double> readOnlyDoubles; [GlobalSetup] public void Setup() { var rand = new Random(); var floats = Enumerable.Range(0, ArrayLength).Select(a => rand.NextSingle()).ToArray(); var doubles = Enumerable.Range(0, ArrayLength).Select(a => rand.NextDouble()).ToArray(); readOnlyFloats = floats; readOnlyDoubles = doubles; } [Benchmark] public double Calc_WaveStatistic_Sum() { return readOnlyFloats.Span.Sum(); } [Benchmark] public double Calc_WaveStatistic_Sum_Double() { return readOnlyDoubles.Span.Sum(); } [Benchmark] public double Calc_WaveStatistic_Avg() { return readOnlyFloats.Span.Avg(); } [Benchmark] public double Calc_WaveStatistic_Avg_Double() { return readOnlyDoubles.Span.Avg(); }
扩展方法实现
public static double Sum(this ReadOnlySpan<float> values) { double sum = 0; for (int i = 0; i < values.Length; i++) sum += values[i]; return sum; } public static double Sum(this ReadOnlySpan<double> values) { double sum = 0; for (int i = 0; i < values.Length; i++) sum += values[i]; return sum; } public static double Avg(this ReadOnlySpan<float> values) { return values.Sum() / values.Length; } public static double Avg(this ReadOnlySpan<double> values) { return values.Sum() / values.Length; }
疑问
按预期,Sum()方法应该比Avg()更快,因为Avg()在Sum()的基础上多执行了一次除法运算,但测试结果显示Avg()反而更快。请问这个结果是否正确?如果正确,原因是什么?
解答
这个结果是可能正确的,核心原因在于JIT编译器的优化行为:
- 返回值的精度优化差异:
Sum()需要完整保留累加后的double精度,而Avg()的最终结果是总和除以长度,JIT可能会对浮点数运算顺序做调整,在累加过程中结合后续除法做精度妥协的优化,减少不必要的精度保留开销。 - 指令流水线的重叠利用:CPU的指令流水线可以在
Sum()的累加循环收尾阶段,提前预准备除法操作,将除法计算与累加的最后几步重叠执行,整体缩短总耗时;而Sum()没有后续操作,无法触发这种并行优化。 - 寄存器分配优化:
Avg()的运算逻辑需要将总和与长度做除法,JIT可能会在累加阶段就为后续除法预留合适的寄存器,避免额外的寄存器拷贝操作;而Sum()直接返回累加值,可能存在多余的寄存器存储步骤。 - 小数据量下的测量误差:如果
ArrayLength较小,单次运算的耗时差异在微秒级别,BenchmarkDotNet的测量误差可能导致结果反常,但如果多次测试均稳定显示Avg()更快,那核心原因还是JIT优化。
内容的提问来源于stack exchange,提问作者Ramga
相关产品推荐
相关产品推荐

