[C#] .NET 8 vs .NET 9 SIMD 加速實測:一般迴圈是否真的能自動向量化

2025-09-17

最近看到一個名詞 SIMD ( Single Instruction, Multiple Data ) ,簡單一句話就是 讓 CPU 以 "一條指令同時處理多筆資料" 的平行運算技術


自 .NET Core 開始,.NET 就在 JIT 編譯器中支援 SIMD,而 .NET 9 更進一步提供了更完整的自動向量化(Auto-Vectorization)能力

使部分迴圈在不修改程式碼的情況下就能獲得向量化的效益,也就是單純迴圈也可以做到 SIMD 的效果?

這邊我只好安裝 .Net 8 跟 .Net9 的環境來進行測試,又是一個燒錢又燒命的測試

程式碼 - 以下為本次測試所使用的加總方法:一個傳統迴圈版本,以及一個使用 Vector<float> 的 SIMD 版本

傳統加總:

static float Sum(float[] values) { float total = 0; for (int i = 0; i < values.Length; i++) total += values[i]; return total; }

使用 

SIMD 加總

/// &lt;summary&gt; /// SIMD 向量化加總 /// &lt;/summary&gt; static float SumSimd(float[] data) { var vectorSize = Vector&lt;float&gt;.Count; var i = 0; var vsum = Vector&lt;float&gt;.Zero; // 每次處理 vectorSize 筆 for (; i &lt;= data.Length - vectorSize; i += vectorSize) { var v = new Vector&lt;float&gt;(data, i); vsum += v; } // 把向量的各元素加起來 var total = 0f; for (int j = 0; j &lt; vectorSize; j++) total += vsum[j]; // 處理尾端剩餘元素 for (; i &lt; data.Length; i++) total += data[i]; return total; }

執行程式碼:

for (var i = 1; i <= 10; i++) { var faker = new Faker("en"); var data = Enumerable.Range(1, 100_000_000) .Select(_ => faker.Random.Float(0, 10)) .ToArray(); var sw = new Stopwatch(); sw.Start(); Sum(data); Console.WriteLine(sw.Elapsed); } Console.WriteLine("--- SIMD ---"); for (var i = 1; i <= 5; i++) { var faker = new Faker("en"); var data = Enumerable.Range(1, 100_000_000) .Select(_ => faker.Random.Float(0, 10)) .ToArray(); var sw = new Stopwatch(); sw.Start(); SumSimd(data); Console.WriteLine(sw.Elapsed); }

比較結果:

//.Net 8 00:00:00.4105529 00:00:00.3609744 00:00:00.3352597 00:00:00.4820423 00:00:00.4234173 00:00:00.3615139 00:00:00.3748291 00:00:00.3548129 00:00:00.3566374 00:00:00.3295502 --- SIMD --- 00:00:00.1451067 00:00:00.1049529 00:00:00.1072769 00:00:00.1048805 00:00:00.0915223 //.Net9 00:00:00.4156275 00:00:00.3431862 00:00:00.4404494 00:00:00.3697095 00:00:00.3433034 00:00:00.3715118 00:00:00.3673285 00:00:00.3541178 00:00:00.3897063 00:00:00.3924788 --- SIMD --- 00:00:00.1194425 00:00:00.1099284 00:00:00.0910654 00:00:00.0905410 00:00:00.1233741


結論 - 即使差異不大,若大量計算還是要用 Vector

以下為本次測試所使用的加總方法:一個傳統迴圈版本,以及一個使用 Vector<float> 的 SIMD 版本

在 .NET 8 上,SIMD 版本的速度遠快於一般迴圈,符合預期

在 .NET 9 上,SIMD 版本仍然具有明顯優勢,而一般迴圈的表現大致與 .NET 8 相近

.NET 9 引入了更多自動向量化(Auto-Vectorization)增強,理論上在某些模式下,傳統迴圈也可能被自動轉換成 SIMD 指令。然而,是否能被向量化,取決於 JIT 的分析能力以及迴圈的結構。此案例中是一個典型的加總迴圈,但因為內容非常簡單、每次迭代都需做一次相依性的累加(total += value),JIT 對這種類型的 sum-reduction 迴圈目前仍無法完全向量化,因此一般迴圈在 .NET 9 的執行時間與 .NET 8 差異不大,屬於正常現象。

反之,手動向量化(使用 Vector<T>)能強制使用 SIMD 指令,因此仍然能得到明顯的加速效果

而且我在MSIL 看來在 .NET8 跟 .NET9 其中 SUM() 是一樣的程式碼,看來這是在 runtime 時期的優化

參考資料:

https://learn.microsoft.com/zh-tw/dotnet/core/whats-new/dotnet-9/overview#:~:text=SIMD





當麻許的碎念筆記 2014 | Donma Hsu Design.