做一个牛逼闪闪的程序员,指的不是技术,是蔑视技术的态度。
cpu与gpu的区别:
- cpu适合做不同的任务,gpu适合做重复性比较多的工作。
- cpu是领导,gpu是板砖的。
以下图示分别是gpu和gpu的硬件组成:
从组成模块上面看,gpu的算数逻辑单元数量众多,是cpu的几百倍。对于重复性的计算,gpu相当于有1024个核在并发执行(注意:此处是于操作系统的并发是两个不同的概念,此处是同一时刻的并发,而操作系统是一个时间段的并发),而cpu只有4个核在执行。速度上面自然是gpu快很多。
以下是实物图:
gpu执行时间对比:
1万次累加运算:
root@-desktop:~/capture/cuda# ./main
GPU运行时间为:71ms
CPU运行时间为:3865ms
root@-desktop:~/capture/cuda#
10万次累加运算:
root@-desktop:~/capture/cuda# ./main
GPU运行时间为:66ms
CPU运行时间为:38538ms
root@-desktop:~/capture/cuda#
可以发现,在一定次数范围内,gpu的性能尚未用完,因此时间稳定在70ms(70ms包括数据从cpu到gpu,gpu运算时间,结果从gpu到cpu的时间)。
执行环境
vmware虚拟机,ubuntu系统。
cuda库
cuda库安装
apt install cuda-nvcc-10-0
设置动态库加载路径,命令加载路径:
root@-desktop:~/# tail /root/.bashrc
# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
#if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
# . /etc/bash_completion
#fi
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda/lib/
export PATH=$PATH:/usr/local/cuda/bin
root@jack-desktop:~/#
代码如下:
/*kernel.cu*/
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "main.h"
#include <stdio.h>
inline void checkCudaErrors(cudaError err)//错误处理函数
{
if (cudaSuccess != err)
{
fprintf(stderr, "CUDA Runtime API error: %s.\n", cudaGetErrorString(err));
return;
}
}
__global__ void add(int *a,int *b,int *c)//处理核函数
{
int tid = blockIdx.x*blockDim.x+threadIdx.x;
for (size_t k = 0; k < 50000; k++)
{
c[tid] = a[tid] + b[tid];
}
}
extern "C" int runtest(int *host_a, int *host_b, int *host_c)
{
int *dev_a, *dev_b, *dev_c;
checkCudaErrors(cudaMalloc((void**)&dev_a, sizeof(int)* datasize));//分配显卡内存
checkCudaErrors(cudaMalloc((void**)&dev_b, sizeof(int)* datasize));
checkCudaErrors(cudaMalloc((void**)&dev_c, sizeof(int)* datasize));
checkCudaErrors(cudaMemcpy(dev_a, host_a, sizeof(int)* datasize, cudaMemcpyHostToDevice));//将主机待处理数据内存块复制到显卡内存中
checkCudaErrors(cudaMemcpy(dev_b, host_b, sizeof(int)* datasize, cudaMemcpyHostToDevice));
add << <datasize / 100, 100 >> >(dev_a, dev_b, dev_c);//调用显卡处理数据
checkCudaErrors(cudaMemcpy(host_c, dev_c, sizeof(int)* datasize, cudaMemcpyDeviceToHost));//将显卡处理完数据拷回来
cudaFree(dev_a);//清理显卡内存
cudaFree(dev_b);
cudaFree(dev_c);
return 0;
}
// main.h
#ifndef __MAIN_H__
#define __MAIN_H__
#define datasize 100 * 1000
#endif
//main.cc
#include "main.h"
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <time.h>
extern "C" int runtest(int *host_a, int *host_b, int *host_c);//显卡处理函数
int main()
{
int a[datasize], b[datasize], c[datasize];
for (size_t i = 0; i < datasize; i++)
{
a[i] = i;
b[i] = i*i;
}
long now1 = clock();//存储图像处理开始时间
runtest(a,b,c);//调用显卡加速
printf("GPU运行时间为:%dms\n", int(((double)(clock() - now1)) / CLOCKS_PER_SEC * 1000));//输出GPU处理时间
long now2 = clock();//存储图像处理开始时间
for (size_t i = 0; i < datasize; i++)
{
for (size_t k = 0; k < 50000; k++)
{
c[i] = (a[i] + b[i]);
}
}
printf("CPU运行时间为:%dms\n", int(((double)(clock() - now2)) / CLOCKS_PER_SEC * 1000));//输出GPU处理时间
/*for (size_t i = 0; i < 100; i++)//查看计算结果
{
printf("%d+%d=%d\n", a[i], b[i], c[i]);
}*/
getchar();
return 0;
}
Makefile
all:
nvcc -c kernel.cu
g++ -std=c++11 -c main.cc
g++ -std=c++11 -o main main.o kernel.o -lcudart -L/usr/local/cuda/lib64
clean:
rm -rf main
区块链挖矿,就是通过碰撞方法,计算出一个符合哈希值的输入,最先算出合法输入的节点被投票成功后,取得记账的主导权,并获得token奖励。 gpu相对于cpu,可以显著的提高哈希运算的效率。
不过说白了,gpu挖矿也没有多少复杂之处。
对于编写服务器的程序员来说,可以在代码中加入gpu来执行循环运算,以节省cpu的宝贵时间,这比一些动不动就大谈协程,http3.0的人要实在一些。