CPU GPU 扫盲帖

x33g5p2x  于2021-11-18 转载在 其他  
字(3.6k)|赞(0)|评价(0)|浏览(282)

摘要

  1. CPU与GPU之间有什么不同?
  2. 为什么需要GPU编程,相比CPU编程,有什么优势?

CPU和GPU之所以大不相同,是由于其设计目标的不同,它们分别针对了两种不同的应用场景。CPU需要很强的通用性来处理各种不同的数据类型,同时又要逻辑判断又会引入大量的分支跳转和中断的处理。这些都使得CPU的内部结构异常复杂。而GPU面对的则是类型高度统一的、相互无依赖的大规模数据和不需要被打断的纯净的计算环境。

所以,与CPU擅长逻辑控制、串行的运算和通用类型数据运算不同,GPU擅长的是大规模并发计算,这也正是密码破解等所需要的。所以,GPU除了图像处理,也越来越多的参与到计算当中来。GPU的工作大部分就是这样,计算量大,但没什么技术含量,而且要重复很多很多次。就像你有个工作需要算几亿次一百以内加减乘除一样,最好的办法就是雇上几十个小学生一起算,一人算一部分,反正这些计算也没什么技术含量,纯粹体力活而已。而CPU就像老教授,积分微分都会算,就是工资高,一个老教授资顶二十个小学生,你要是富士康你雇哪个?GPU就是这样,用很多简单的计算单元去完成大量的计算任务,纯粹的人海战术。这种策略基于一个前提,就是小学生A和小学生B的工作没有什么依赖性,是互相独立的。很多涉及到大量计算的问题基本都有这种特性,比如你说的破解密码,挖矿和很多图形学的计算。这些计算可以分解为多个相同的简单小任务,每个任务就可以分给一个小学生去做。但还有一些任务涉及到“流”的问题。比如你去相亲,双方看着顺眼才能继续发展。总不能你这边还没见面呢,那边找人把证都给领了。这种比较复杂的问题都是CPU来做的。

总而言之,CPU和GPU因为最初用来处理的任务就不同,所以设计上有不小的区别。而某些任务和GPU最初用来解决的问题比较相似,所以用GPU来算了。GPU的运算速度取决于雇了多少小学生,CPU的运算速度取决于请了多么厉害的教授。教授处理复杂任务的能力是碾压小学生的,但是对于没那么复杂的任务,还是顶不住人多。当然现在的GPU也能做一些稍微复杂的工作了,相当于升级成初中生高中生的水平。但还需要CPU来把数据喂到嘴边才能开始干活,究竟还是靠CPU来管的。什么类型的程序适合在GPU上运行:

  1. 计算密集型的程序。所谓计算密集型(Compute-intensive)的程序,就是其大部分运行时间花在了寄存器运算上,寄存器的速度和处理器的速度相当,从寄存器读写数据几乎没有延时。可以做一下对比,读内存的延迟大概是几百个时钟周期;读硬盘的速度就不说了,即便是SSD, 也实在是太慢了。
  2. 易于并行的程序。GPU其实是一种SIMD(Single Instruction Multiple Data)架构, 他有成百上千个核,每一个核在同一时间最好能做同样的事情。

第一次知道有显卡(GPU)编程这个东西,是去年比特币最热门的时候,看了几篇关于比特币的文章,说比特币挖矿要靠显卡,CPU的速度与GPU根本就没法比,于是就非常好奇,显卡是什么神奇的东西?为什么运算速度会比CPU快很多?当时也只是好奇而已,根本没想过这东西会与自己有任何关系。

去年年底的时候,我开始研究机器学习,试着用PHP编了几个遗传算法和神经网络算法的程序,发现很有趣,功能很强大,我一直想做医学方面的人工智能开发,觉得机器学习这个东西很有用,但就是运算速度太慢,估算了一下按程序的运行速度,要初略解决我的问题至少要算一两个星期。如果要以较高的精确度解决我的问题,可能要算几个月。仔细权衡利弊之后,我决定从头学C语言,毕竟C是高级语言中运算速度最快的(现在后悔,当时要从C++开始学就更好了)。从初学到把我的php程序改写为C,一共花了两个星期左右,可喜的是运算速度提高了大约150倍。

后来发现神经网络用遗传算法来驱动远不如用退火算法驱动效率高,并且神经网络算法可以去掉很多冗余计算。这样一来,我的算法效率前前后后又提高了一万多倍。与最初的PHP程序相比,运算效率已经提高了大约200万倍。 尽管如此,我还是不满意,因为问题稍微复杂些,且要求的精度再高些,我的电脑还是要没日没夜转好几天。我希望程序运算速度能够再有至少一个数量级的提升:但是在软件上能改进的地方几乎都改进了,只能在硬件上想办法了。

我本以为,按照摩尔定律,CPU的运算速度每一年半要提升一倍。不怕大家笑话,我现在的电脑是2007年买的,已经过去七年了,最新的CPU速度应该提升二十多倍了。于是,我上网查了一下,竟然发现最新款的电脑,CPU的主频不过比我的多10%左右,这是怎么回事?一查才知道,原来CPU的摩尔定律到2008年左右就失效了。这么多年来CPU主频都没有大的变化,主要靠不断增加CPU的数量(双核、四核、八核…)进一步提高电脑性能。但这种多核结构对于我要解决的问题,帮助似乎并不明显。

于是我就想到比特币文章中提到的GPU运算——这个从来没觉得会与自己有关系的东西。

查了一些文章,大致了解到GPU之所以比CPU快得多,并不是GPU的处理器运算速度更快——其实目前最好的显卡,处理器的主频也不到CPU的一半。但是CPU只有一个处理器,而GPU的处理器少则几十个,多则几千个。一只手干活干得再快,也没有成百上千只手一起干活干得快,就是这个道理。

GPU这个特点决定了并不是所有程序都适合用GPU来加速,只有你的问题能够分解为若干能够独立执行的部分(即一部分程序的运算,并不依赖于另一部分运算的运行结果),才适合考虑用GPU来处理。 这也是GPU编程的核心观念:并行运算

既然GPU是成百上千只手一起干活,那么GPU的价格为什么不是CPU的成百上千倍呢?关键就在于:GPU的“手”与CPU的“手”相比是带有明显残疾的,只有完成某些特定动作的时候效率高,完成其他动作效率就很低。 具体表现在:

  1. 所有的“手”(或者叫处理器、线程)完成相同动作时效率高,完成不同动作时效率低——这一条是显卡编程最关键、最核心的部分。这决定了GPU虽然有几千只手,但不可能像工厂工人那样进行流水作业,你装填,我打包,他装箱,这对于GPU是行不通的。 大家都一起打包,然后大家一起来装箱,只有这样的方式才适合让GPU来处理。
  2. 如果各个并行的部分(即各个线程),需要共享大量数据,那么不适合用GPU进行处理。要注意,我说的是“不能共享大量数据”,并不是说GPU不适合处理大量数据。相反,由于GPU具有较大的显存空间(比较差的显卡也有2G显存)和非常快的数据吞吐速度(专业术语叫带宽),所以非常适合做大数据的处理。GPU编程的一个早期经典案例就是医学图像的处理:据说有个医生发明了一种彩超快速诊断子宫肌瘤的方法,但是如果用CPU处理几个T的彩超检查数据的话,几天都搞不定。后来,改用GPU处理,几十分钟就解决了——所以,处理大数据是GPU的强项。
    但这是指各个线程独立的读取一部分专属于自己的数据,那么处理的速度可以很高。如果大量的线程,要相互交错的同时访问大量数据那么运行效率就很低。打个比方:菜市场每一个摊位相当于一个要被访问的数据,逛菜市场的人相当于不同的线程,那么大家杂乱无章的在市场里乱逛,运行效率就很低。如果大家排好队进场,规定一个人只准面对一个摊位,那么运行效率就会很高。
  3. 并行处理的线程数不能太少。如果你的程序只能分解为几百个并行运算的部分,就不适合用GPU来处理——至少要有几千个并行的线程才能勉强体现出GPU的优势。如果你的程序撑死了也就分解为两三千个并行的部分,那么还是建议你不要考虑用GPU加速了。举个例子,我用GPU运行我的神经网络(我的显卡非常差,只有48个处理器),刚把程序运行通的时候,我安排了1024个线程进行测试,与我原来的CPU程序相比,速度只提高了20%左右,让我大失所望。后来发发狠,把并行的线程数安排到8192个——速度竟然提高到了原来的八倍左右——这让我欣喜若狂。这意味着如果我换更好的显卡,比如有两千多个处理器的显卡,那么我的程序速度还有四五十倍的提升空间,这样一来我的算法速度有望比在CPU的速度提高2-3个数量级,想想都让人兴奋。

题外话,要学显卡编程,一定要对C/C++比较熟练,对指针的运用比较自如,才可能进行显卡编程——也可以说距离显卡编程就很近了。据说很久很久以前…显卡编程是一件非常麻烦的大工程。后来一种叫CUDA的东西横空出世——显卡厂商NVIDIA推出的显卡运算平台——显卡编程就变得非常简单了,只要在熟练C的前提下,学几个简单的语句就可以搞定。

转载自知乎用户对《CPU 和 GPU 的区别是什么?》问题的回答以及张纯睿《CUDA显卡运算编程菜鸟入门指南1——Hello world - yfszzx的专栏 - 博客频道 - CSDN.NET》 一文。

相关文章