Switch 语句优于 set 语句

问题描述 投票:0回答:1

我正在对 ref structs 和 text-ValueType 进行测试
并在结构构造函数中工作时陷入了这个疑问。

显然,使用 i 式循环控制 ref 变量的 switch 语句比在结构体字段中手动设置数组位置要快。

我不确定顶级声明方法中这种测试的有效性,但是


这是代码

using System.Diagnostics; const string testText = $""" Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque orci purus, vulputate vulputate """; const int load_Steps = 250; CharblockExample bySetBlock ; CharblockExample bySwitchBlock; var watcher = Stopwatch.StartNew(); var results = new List<(TimeSpan tic1, TimeSpan tic2)>(); try { for (int i = 0; i < load_Steps; i++) { var start_tics = watcher.Elapsed; bySwitchBlock = new(testText.AsSpan(), true); var ticBlock2 = watcher.Elapsed - start_tics; start_tics = watcher.Elapsed; bySetBlock = new(testText.AsSpan(), false); var ticBlock1 = watcher.Elapsed - start_tics; Console.WriteLine($"{nameof(bySetBlock)} and {nameof(bySwitchBlock)}: {ticBlock1} vs {ticBlock2}"); results.Add((ticBlock1, ticBlock2)); } } finally { watcher.Stop(); Console.WriteLine(); var overall_1 = results.Sum(element => element.tic1.Microseconds); var overall_2 = results.Sum(selector => selector.tic2.Microseconds); var overall_result = overall_1 - overall_2; Console.WriteLine($"overall analysis: {(overall_1 is < 0 ? $"{nameof(bySetBlock)} was {Math.Abs(overall_result)} ms faster than {nameof(bySwitchBlock)}" : $"{nameof(bySwitchBlock)} was {Math.Abs(overall_result)} ms faster than {nameof(bySetBlock)}" )}"); } public readonly ref struct CharblockExample { private readonly int inputtedLength; private readonly bool _input = false; private readonly char //char spots #region Char-Spots _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10; #endregion public CharblockExample(ReadOnlySpan<char> chars, bool performTest) { _input = true; Span<char> arr = stackalloc char[MAX_LENGTH]; inputtedLength = chars.Length; if (chars.Length > MAX_LENGTH) throw new ArgumentOutOfRangeException(nameof(chars), $""" The provided char array is longer than the max of 256 chars for this block. """); for (int i = 0; i < MAX_LENGTH; i++) { if (i >= chars.Length) break; arr[i] = chars[i]; } if (performTest) { int pos = 0; ref var _ref = ref _1; while (pos < MAX_LENGTH - 1) { switch (pos) { case 0: _ref = ref _0; break; case 1: _ref = ref _1; break; case 2: _ref = ref _2; break; case 3: _ref = ref _3; break; case 4: _ref = ref _4; break; case 5: _ref = ref _5; break; case 6: _ref = ref _6; break; case 7: _ref = ref _7; break; case 8: _ref = ref _8; break; case 9: _ref = ref _9; break; case 10: _ref = ref _10; break; } pos++; _ref = arr[pos]; } } else { _0 = arr[0]; _1 = arr[1]; _2 = arr[2]; _3 = arr[3]; _4 = arr[4]; _5 = arr[5]; _6 = arr[6]; _7 = arr[7]; _8 = arr[8]; _9 = arr[9]; _10 = arr[10]; } } public char[] CharArr => new[] { _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10 }; private const int MAX_DISPLAYABLE = 15; private const int MAX_LENGTH = 256; }

这是我完全执行后的结果:

总体分析:bySwitchBlock 比 bySetBlock 快 1240 毫秒

根据我的判断,只有在不检查任何布尔逻辑或推进整数索引器的情况下进行设置应该更快,它只是我所看到的命令的内联执行
c# switch-statement performance-testing
1个回答
0
投票
BenchmarkDotNet

测试问题的

first revision
中的 CharblockExample 得出的结果是,使用 switch 比不使用它慢约 2 倍。

BenchmarkDotNet v0.13.7,Windows 10(10.0.19045.3086/22H2/2022更新)

Intel Core i7-6700 CPU 3.40GHz (Skylake),1 个 CPU,8 个逻辑核心和 4 个物理核心

.NET SDK 7.0.304

[主机]:.NET 7.0.7 (7.0.723.27404)、X64 RyuJIT AVX2

默认作业:.NET 7.0.7 (7.0.723.27404)、X64 RyuJIT AVX2

方法开关无开关
意思是 错误 标准偏差
363.3 纳秒 7.18 纳秒 11.18 纳秒
170.2 纳秒 3.44 纳秒 3.96 纳秒
这是可以预料到的。你在那里做了很多额外的工作 - 控制循环,用跳转表跳转等等。如果抖动可以识别模式并将无开关代码中的一系列分配优化为速度更快。

这是基准代码:

public class Benchmark { const string testText = $""" Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque orci purus, vulputate vulputate mattis quis, accumsan in turpis. Vestibulum quis sapien iaculis, pulvinar magna sed, lacinia lectus. Donec nec felis nec metus dictum aliquet vel non. """; [Benchmark] public CharblockExample Switch() => new CharblockExample(testText, true); [Benchmark] public CharblockExample NoSwitch() => new CharblockExample(testText, false); } public class Program { public static void Main(string[] args) { var summary = BenchmarkRunner.Run<Benchmark>(); } }

通常,像这样的微基准测试代码会产生相当不准确的结果。许多外部因素都会影响最终结果。你应该使用

© www.soinside.com 2019 - 2024. All rights reserved.