對 32,768(2^15)個四維向量按模長(歐幾里得範數)排序,初始演算法 A 耗時 534ms,如何大幅提升效能?
class VectorComparer : IComparer<Vector> {
public int Compare(Vector c1, Vector c2) {
double x = Math.Sqrt(c1.X*c1.X + c1.Y*c1.Y + c1.Z*c1.Z + c1.W*c1.W);
double y = Math.Sqrt(c2.X*c2.X + c2.Y*c2.Y + c2.Z*c2.Z + c2.W*c2.W);
return x.CompareTo(y);
}
}
Array.Sort(vectors, new VectorComparer());
// 耗時:534ms
問題:比較器被呼叫 O(N log N) 次,每次重複計算平方根與冪次,極度浪費 CPU。
for (int i = 0; i < n; i++) {
vectors[i].T = Math.Sqrt(vectors[i].X*vectors[i].X + ...); // 預計算
}
Array.Sort(vectors, new VectorComparer2()); // 比較 T 欄位
// 耗時:16ms(快 33 倍!)
關鍵優化:
Math.Pow 呼叫開銷,改用直接乘法double 比較
vectors[i].T = Math.Sqrt(vectors[i].X * vectors[i].X + ...); // 乘法比 Pow 快
// 耗時:12ms(再提升 ~25%)
| 版本 | 耗時 | 加速比 | 核心改進 |
|---|---|---|---|
| A | 534 ms | 1x | 基準 |
| B | 16 ms | 33x | 預計算模長、消除重複運算 |
| C | 12 ms | 44x | 乳法替換 Pow、減少函數呼叫 |
使用 PLINQ 平行排序:
vectors.AsParallel().OrderBy(v => v.T).ToArray();
// 或
Array.Sort(vectors, (a,b) => a.T.CompareTo(b.T)); // 單執行緒已極快,並行開銷反而較大
對於已優化至 12ms 的情況,並行化因任務分割、合併開銷反而變慢。並行適合「單元運算昂貴」且「資料量極大」場景。
struct Vector 避免堆積分配與 GC 壓力System.Numerics.Vector<T> 批次計算 4/8 個元素Sqrt演算法複雜度優於並行化;資料局部性與記憶體存取模式決定實際效能。
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Vector4Test {
public class Vector {
public double W, X, Y, Z, T;
}
class VectorComparer : IComparer<Vector> { ... } // 版本 A
class VectorComparer2 : IComparer<Vector> { ... } // 版本 B/C
class Program {
static void Main() {
var vectors = GetVectors();
Benchmark("A", vectors, v => Array.Sort(v, new VectorComparer()));
vectors = GetVectors();
Benchmark("B", vectors, v => { Precompute(v); Array.Sort(v, new VectorComparer2()); });
vectors = GetVectors();
Benchmark("C", vectors, v => { PrecomputeFast(v); Array.Sort(v, new VectorComparer2()); });
}
static Vector[] GetVectors() { ... }
static void Precompute(Vector[] v) { ... }
static void PrecomputeFast(Vector[] v) { ... }
static void Benchmark(string name, Vector[] v, Action<Vector[]> act) { ... }
}
}
從 534ms 到 12ms,並非靠並行硬體,而是演算法重構。這是效能優化的鐵律:先做對(正確性),再做快(複雜度),最後才做並行。