日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C#的GPU加速方法

發布時間:2024/1/8 C# 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C#的GPU加速方法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前往我的主頁以獲得更好的閱讀體驗C#的GPU加速方法 - DearXuan的主頁https://blog.dearxuan.com/2021/08/13/C-%E7%9A%84GPU%E5%8A%A0%E9%80%9F%E6%96%B9%E6%B3%95/

本文將通過C#調用dll的方法來實現并發計算

在VS2019里新建動態鏈接庫項目,在pch.h里定義函數

// pch.h: 這是預編譯標頭文件。 // 下方列出的文件僅編譯一次,提高了將來生成的生成性能。 // 這還將影響 IntelliSense 性能,包括代碼完成和許多代碼瀏覽功能。 // 但是,如果此處列出的文件中的任何一個在生成之間有更新,它們全部都將被重新編譯。 // 請勿在此處添加要頻繁更新的文件,這將使得性能優勢無效。#ifndef PCH_H #define PCH_H// 添加要在此處預編譯的標頭 #include "framework.h" extern "C" _declspec(dllexport) void Sum(int* s,int a[],int b[],int length);#endif //PCH_H

在pch.cpp里實現該函數

// pch.cpp: 與預編譯標頭對應的源文件#include "pch.h" #include <amp.h>// 當使用預編譯的頭時,需要使用此源文件,編譯才能成功。using namespace Concurrency;extern "C" _declspec(dllexport) void Sum(int* s, int a[], int b[],int length) {array_view<const int, 1> aArray(length, a);array_view<const int, 1> bArray(length, b);array_view<int, 1> sum(length, s);parallel_for_each(sum.extent,[=](index<1> idx) restrict(amp) {sum[idx] = aArray[idx] + bArray[idx];}); }

該函數接收4個參數,分別用來儲存結果,a數組,b數組,數組長度,并將a和b數組相加,結果儲存在s里面。

array_view表示包含在一個容器中的數據的N維視圖,各項參數的含義如下:

????????const int:類型,

????????1:維數

????????aArray:array_view的實例

????????length:長度

????????a:數據源

如果是二維數組,則要改成下面的形式

array_view<const int, 2> aArray(width,height, a);

parallel_for_each語句能夠進行并發計算,index<1>指idx是一維的,如果是二維數組,需要改成index<2>,此時idx相當于(i,j),通過idx[0]和idx[1]獲得行號和列號

例如

int row = idx[0]; int col = idx[1];

aArray[idx]和aArray(row,col)是等效的

將上述代碼生成dll,并放在C#程序的目錄下

導入剛剛寫的dll

[DllImport("Dll1.dll", EntryPoint = "Sum", CallingConvention = CallingConvention.Cdecl)] public static extern void Sum(IntPtr s,int[] a, int[] b,int length);

生成隨機數數組,求和

static void Main(string[] args) {const int size = 100;int[] s = new int[size];int[] a = new int[size];int[] b = new int[size];Random random = new Random();for(int i = 0; i < size; i++){a[i] = random.Next(0, 100);b[i] = random.Next(100, 200);}unsafe{IntPtr p = Marshal.UnsafeAddrOfPinnedArrayElement(s, 0);Sum(p, a, b, size);}for(int i = 0; i < size; i++){Console.WriteLine(a[i] + "+" + b[i] + "=" + s[i]);}Console.ReadLine(); }

使用StopWatch類來計算耗時(命名空間System.Diagnostics)

Stopwatch watch1 = new Stopwatch(); watch1.Start(); for(int i = 0; i < size; i++) {s[i] = a[i] + b[i]; } watch1.Stop(); Console.WriteLine("CPU耗時:" + watch1.Elapsed.TotalMilliseconds); Stopwatch watch2 = new Stopwatch(); watch2.Start(); Sum(p, a, b, size); watch2.Stop(); Console.WriteLine("GPU耗時:" + watch2.Elapsed.TotalMilliseconds);

由于加載dll本身需要時間,所以在計時之前需要先調用一次Sum函數。

測試代碼是計算4億個數的和,可以看到GPU計算比CPU計算少了300毫秒,但是CPU在循環2億次的情況下居然僅僅比GPU多了300毫秒,這是因為GPU無法從內存讀取數據,需要把數據先復制到顯存里才能計算,計算完又需要把數據復制回來,而主要時間開銷都在數據的復制里面。

現實情況下,循環體里不可能只有一行代碼,假設循環體里有10個語句,那么CPU的執行時間就會翻10倍,而GPU的執行時間也會翻10倍,但是由于主要耗時操作是數據的復制,所以實際增長不會特別明顯。

下面我們修改一下代碼。

extern "C" _declspec(dllexport) void Sum(int* s, int a[], int b[],int length) {array_view<const int, 1> aArray(length, a);array_view<const int, 1> bArray(length, b);array_view<int, 1> sum(length, s);parallel_for_each(sum.extent,[=](index<1> idx) restrict(amp) {sum[idx] = aArray[idx] + bArray[idx];if (idx[0] % 5 == 0) {sum[idx] += 5;}if (idx[0] % 7 == 0) {sum[idx] += 7;}if (idx[0] % 11 == 0) {sum[idx] += 11;}if (idx[0] % 13 == 0) {sum[idx] += 13;}if (idx[0] % 17 == 0) {sum[idx] += 17;}}); } watch1.Start(); for(int i = 0; i < size; i++) {s[i] = a[i] + b[i];if (i % 5 == 0){s[i] += 5;}if (i % 7 == 0){s[i] += 7;}if (i % 11 == 0){s[i] += 11;}if (i % 13 == 0){s[i] += 13;}if (i % 17 == 0){s[i] += 17;} } watch1.Stop(); Console.WriteLine("CPU耗時:" + watch1.Elapsed.TotalMilliseconds);

這次改用100萬量級的數據

?現在GPU的優勢就完全體現出來了

總結

以上是生活随笔為你收集整理的C#的GPU加速方法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。