用 C# 寫 CUDA 程式
自從生成式 AI 開始流行後,GPU 運算逐漸被大家重視,甚至搶購 N 家的顯示卡,看上的就是它的 CUDA,其實 CUDA 發展數十年了,直到 AI 火紅後才被重視。一般而言,都是使用 C++ 來開發 CUDA 程式,不過使用 C# 也是能呼叫的,以下會介紹如何使用。
首先是在 nuget 中安裝 ILGPU 套件,然後新增下列 Struct:
public struct User
{
public User() { }
public int UserId { get; set; } = 0;
public double Credit { get; set; } = 0;
public double Odd { get; set; } = 0;
public double WinLoss { get; set; } = 0;
public int IsWin { get; set; } = 0;
}
這個是用來模擬結算用的資料結構,接下來是範例程式碼:
//prepare datas
List<User> list = new List<User>();
int max = 100_000_000;
for (int i = 0; i < max; i++)
{
list.Add(new User { UserId = Guid.NewGuid().ToString().GetHashCode(), IsWin = 1, Odd = 3.5f, Credit = 8 });
}
Console.WriteLine("datas completed.");
首先是準備1億筆的資料,接下來再使用 GPU 來做計算,程式碼如下:
Stopwatch stopwatch = Stopwatch.StartNew();
Context context = Context.CreateDefault();
Accelerator accelerator = context.CreateCudaAccelerator(0);
//Accelerator accelerator = context.CreateCPUAccelerator(0);
var deviceData = accelerator.Allocate1D<User>(list.ToArray());
var deviceOutput = accelerator.Allocate1D<User>(new User[list.Count]);
// load / compile the kernel
var loadedKernel2 = accelerator.LoadAutoGroupedStreamKernel(
(Index1D i, ArrayView<User> data, ArrayView<User> output) =>
{
output[i] = new User();
if (data[i].IsWin == 1)
{
output[i].UserId = data[i].UserId;
output[i].WinLoss = data[i].Odd * data[i].Credit;
}
});
loadedKernel2((int)deviceOutput.Length, deviceData.View, deviceOutput.View);
accelerator.Synchronize();
//Stock Logic
User[] userDatas = new User[deviceOutput.Length];
deviceOutput.CopyToCPU(userDatas);
accelerator.Dispose();
context.Dispose();
stopwatch.Stop();
Console.WriteLine($"Total Time: {stopwatch.ElapsedMilliseconds}ms");
重點在於:
var deviceData = accelerator.Allocate1D<User>(list.ToArray());
var deviceOutput = accelerator.Allocate1D<User>(new User[list.Count]);
這兩個陣列的個數一定要一樣,而下列就是放計算的邏輯:
var loadedKernel2 = accelerator.LoadAutoGroupedStreamKernel(
(Index1D i, ArrayView<User> data, ArrayView<User> output) =>
{
output[i] = new User();
if (data[i].IsWin == 1)
{
output[i].UserId = data[i].UserId;
output[i].WinLoss = data[i].Odd * data[i].Credit;
}
});
初步試出來的結果是,用 CPU 算要99秒,而 GPU 只要15秒,差別滿大的,但個人認為這還是比較適合科學計算,一般系統的大量資料計算主要還是卡I/O,效果可能不明顯。
參考資料