你所写的内核是完全串行的。每个启动执行的线程都将执行相同的工作。
CUDA(以及OpenCL和其他类似的“单程序,多数据”类型编程模型)背后的主要思想是,你会进行“数据并行”操作 - 所以需要执行相同的、大部分独立的操作多次 - 并编写一个可以执行该操作的内核。然后启动大量(半)自主线程在输入数据集上执行该操作。
在数组添加示例中,数据并行操作是:
C[k] = A[k] + B[k]
对于所有k在0到128 * 1024之间的情况。每个加法操作都是完全独立的,没有排序要求,因此可以由不同的线程执行。为了在CUDA中表示这个,可能会像这样编写内核:
__global__ void mAdd(float* A, float* B, float* C, int n)
{
int k = threadIdx.x + blockIdx.x * blockDim.x;
if (k < n)
C[k] = A[k] + B[k];
}
[免责声明:代码是在浏览器中编写的,未经测试,使用风险自负]
这里,串行代码中的内部和外部循环被一个CUDA线程代替进行每个操作,并且我在代码中添加了一个限制检查,以便在启动的线程数超过所需操作数的情况下,不会发生缓冲区溢出。如果像这样启动内核:
const int n = 128 * 1024;
int blocksize = 512; // value usually chosen by tuning and hardware constraints
int nblocks = n / blocksize; // value determine by block size and total work
madd<<<nblocks,blocksize>>>mAdd(A,B,C,n);
然后,将启动256个块,每个块包含512个线程,以并行执行数组加法操作。请注意,如果输入数据大小不能表示为块大小的整数倍,则块数需要上取整以覆盖完整的输入数据集。
上述所有内容都是对CUDA范式进行了极度简化的概述,只是一个非常微不足道的操作,但也许足够让您继续学习。如今,CUDA已经相当成熟,并且有很多好的、免费的教育材料在网上流传,您可以使用它们来进一步阐明我在此答案中忽略的编程模型的许多方面。
C[i] = A[i] + B[i]
语句即可完成操作。具体见demo.py。 - jfs