GPU 的并行計算能力高于 CPU,所以最近也有很多利用 GPU 的項目出現在我們的視野中,在 InfoQ 上看到這篇介紹 Accelerator-V2 的文章,它是微軟研究院的研究項目,需要注冊后才能下載,感覺作為我接觸 GPU 通用運算的第一步還不錯,于是去下載了回來。
?
在安裝包里,包含了幾個例子程序,比如著名的 Life 游戲,不過,Life 游戲,相對于剛接觸 GPU 運算的我,還是稍顯復雜了。于是簡化一下,只是進行一些簡單的計算,發現,DX9Target.ToArray 如果返回參數是 int 數組的話,則會爆出“未支持的操作”的異常,想想也對,顯卡確實是精于浮點運算的。
?
本來,我以為,GPU 運算是 DirectX 11 才有的功能,但是 Accelerator 支持的卻是 DirectX 9,想來 DirectX 11 支持的運算能力更高、方式更簡單吧。
?
為了簡單比較一下 CPU 和 GPU 的速度,也寫了一個 .net 4 的并行運算的程序,因為 DX9Target 不支持 int,所以這里的數組也用 float,如下:
?
?

private const int GridSize = 1024; private float[] _map;public Form1() {InitializeComponent();_map = new float[GridSize * GridSize];for (int y = 0; y < GridSize; y++){for (int x = 0; x < GridSize; x++){_map[x * GridSize + y] = x * y;}}Render(); }private void Start_Click(object sender, EventArgs e) {var stopwatch = new Stopwatch();stopwatch.Start();_map = _map.AsParallel().Select(p => p * p * p / 4 + 194).ToArray();var time = stopwatch.ElapsedMilliseconds;this.Text = time.ToString();Render(); }private void Render() {var workingBitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);for (int y = 0; y < pictureBox1.Height; y++){for (int x = 0; x < pictureBox1.Width; x++){workingBitmap.SetPixel(x, y, Color.FromArgb(-0x1000000 | (int)_map[x * 2 * GridSize + y * 2]));}}pictureBox1.Image = workingBitmap; }
?
?
而使用 Accelerator 的代碼如下:
?
?

private const int GridSize = 1024; private readonly DX9Target _target; private float[,] _map;public Form1() {InitializeComponent();_target = new DX9Target();_map = new float[GridSize, GridSize];for (int y = 0; y < GridSize; y++){for (int x = 0; x < GridSize; x++){_map[x, y] = x * y;}}Render(); }private void Start_Click(object sender, EventArgs e) {var stopwatch = new Stopwatch();stopwatch.Start();var p = new FloatParallelArray(_map);p = p * p * p / 4 + 194;_target.ToArray(p, out _map);var time = stopwatch.ElapsedMilliseconds;this.Text = time.ToString();Render(); }private void Render() {var workingBitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);for (int y = 0; y < pictureBox1.Height; y++){for (int x = 0; x < pictureBox1.Width; x++){workingBitmap.SetPixel(x, y, Color.FromArgb(-0x1000000 | (int)_map[x * 2, y * 2]));}}pictureBox1.Image = workingBitmap; }
?
?
?
用我的筆記本(CPU 為 Core i5 430, 顯卡為 ATI 5650)測試,對它們兩個程序,都點擊幾次 Start 按鈕,發現運行 3 次左右,圖片框會變成全黑,這時,普通并行程序運算速度變慢,而 GPU 程序運行速度無明顯變化,普通并行程序 4 次值為:96,89,277,291,而 GPU 程序 4 次值為:71,40,35,50。單就這個測試來說,在我的電腦上,使用 GPU 的程序,大概比普通并行程序快一倍左右吧。這個測試本身,其實不見得很公平,結果僅供參考。
?
不過,在 Accelerator 中的并行編程,明顯感覺受到的約束很大,平常很容易的代碼,要改成這種并行模式,需要花費很多力氣,有些邏輯甚至無法實現。相對于 Accelerator,Brahma 的代碼寫起來就容易得多,也更易于閱讀,其 Life 游戲的例子程序讀起來簡單而清晰,可惜我編譯了 Brahma v0.1 和 v0.4,在我的電腦上,DirectX 的例子程序沒有效果,而 OpenGL 的例子程序則會報一個“The generated GLSL was invalid”的異常,看來還需要等它完善之后才能使用吧。