关于多CPU、多核和多线程
关于CPU的多核和超线程技术
- CPU的物理个数由主板上的插槽数量决定,每个CPU可以有多核心,每核心可能会有多线程。
- 多核CPU的每核(每核都是一个小芯片),在OS看来都是一个独立的CPU。
- 对于超线程CPU来说,每核CPU可以有多个线程(数量是两个,比如1核双线程,2核4线程,4核8线程),每个线程都是一个虚拟的逻辑CPU(比如Windows下是以逻辑处理器的名称称呼的),而每个线程在OS看来也是独立的CPU。
这是欺骗操作系统的行为,在物理上仍然只有1核,只不过在超线程CPU的角度上看,它认为它的超线程会加速程序的运行。
- CPU的多线程和程序的多线程是不同的,CPU的多线程是硬件多线程,程序的多线程是软件多线程,软件多线程定义的是多个并发执行的任务分支,硬件的多线程是可以被当作一个CPU核心来调度执行任务的CPU资源。
- 要发挥超线程优势,需要操作系统对超线程有专门的优化。
- 超线程的CPU在能力上,比非多线程的CPU核心要更强,但每个线程不足以与独立的CPU核心能力相比较。
- 每核上的多线程CPU都共享该核的CPU资源。
例如,假设每核CPU都只有一个”发动机”资源,那么线程1这个虚拟CPU使用了这个”发动机”后,线程2就没法使用,只能等待。
所以,超线程技术的主要目的是为了增加流水线(参见前文对流水线的解释)上更多个独立的指令,这样线程1和线程2在流水线上就尽量不会争抢该核CPU资源。所以,超线程技术利用了superscalar(超标量)架构的优点。 - 多线程意味着每核可以有多个线程的状态。比如某核的线程1空闲,线程2运行。
- 超线程没有提供完全意义上的并行处理,每核CPU在某一时刻仍然只能运行一个进程,因为线程1和线程2是共享某核CPU资源的。可以简单的认为每核CPU在独立执行进程的能力上,有一个资源是唯一的,线程1获取了该资源,线程2就没法获取。(稍后会深入解释超线程如何实现并行运行)
但是,线程1和线程2在很多方面上是可以并行执行的。比如可以并行取指、并行解码、并行执行指令等。所以虽然单核在同一时间只能执行一个进程,但线程1和线程2可以互相帮助,加速进程的执行。
并且,如果线程1在某一时刻获取了该核执行进程的能力,假设此刻该进程发出了IO请求,于是线程1掌握的执行进程的能力,就可以被线程2获取,即切换到线程2。这是在执行线程间的切换,是非常轻量级的。(WIKI: if resources for one process are not available, then another process can continue if its resources are available) - 多线程可能会出现一种现象:假如2核4线程CPU,有两个进程要被调度,那么只有两个线程会处于运行状态,如果这两个线程是在同一核上,则另一核完全空转,处于浪费状态。更期望的结果是每核上都有一个CPU分别调度这两个进程。
CPU多线程和程序多线程的关系和区别
- 程序的多线程,是软件多线程;多个软线程提供了多任务并发执行的可能性。
- CPU里的线程数是超线程,是硬件多线程。每个硬件多线程(超线程)可以看作是逻辑cpu,但并非是完全意义上的CPU。
CPU核心中的超线程共享该核心中的部分功能单元,比如超线程1执行加法运算时,超线程2可以执行乘法运算,但超线程2不能同时执行加法运算,只是举个例子来说明,并非合理,不过也由此可知,超线程这种逻辑CPU是不能当作一个完整核心的物理CPU来看待的。此外,由于每个超线程都是CPU资源,可以独立运行任务,所以每个超线程都具有自己的执行状态,比如要有自己的寄存器,有自己的PC。
另一方面,超线程因为都在核心内,它们共享该核心的L1和L2高速缓存,所以每个核心内的L1和L2需要有专门的缓存控制器,需要有专门的缓存策略。
再回头来说多进程以及软件多线程的调度问题。
无论是多进程还是软件多线程,它们所表示的含义都是可并发执行的多个任务分支,如果是在多处理器、多核、或超线程CPU下,这些并发任务就可以被并行执行,所以多进程、软件多线程都可以被调度分配到超线程上执行,因为超线程是可以独立执行任务的CPU资源。
多颗CPU
对于多颗CPU的架构组织方式,有:
- AMP(Asymmetric multiprocessing):非对称多处理器结构
- SMP(Symmetric multiprocessing):对称多处理器结构
- UMA(Uniform memory access):一致存储访问结构
- NUMA(Non-uniform memory access):非一致存储访问结构
- MPP(massively parallel processing):大规模(海量)并行处理结构
通常会拿来说明的是SMP和NUMA,MPP是海量并行处理结构。
SMP
对称多处理结构,认为所有CPU的角色是平等的,所有CPU都共享内存、总线等资源。其实单颗多核的CPU内部的多核组织方式也是SMP结构,所有的核心都共享内存、总线资源。
对于SMP结构来说,由于每颗CPU都需要操作共享存储:内存,所以需要保证内存数据的一致性(即缓存一致性)。比如CPU1里的Core1修改数据A,假如采用bus snooping缓存一致性策略,需要在总线发送广播通知所有CPU的所有Core使它们对数据A的缓存失效。如果CPU数量较少,问题并不大,但是随着CPU数量增多,因缓存一致性和共享对象导致的总线流量会暴增。
所以SMP结构并不利于扩展更多CPU,比如2-4颗CPU可考虑SMP架构,但4颗CPU以上便不适合使用SMP。
NUMA
NUMA(非一致存储访问结构)结构使得各个CPU有自己的内存资源,通过各CPU之间的互联模块,各CPU也可以访问其它CPU的内存资源。
因为CPU都有自己本地的内存,可以各自管理自己的内存保证自己的缓存一致性。但是,因为各CPU各自的内存分离开了,使得CPU1通过互联模块访问CPU2的内存速度很慢(因为通过中间数据传输介质且距离更远),所以使用NUMA结构时,程序应尽量避免CPU之间的交互并行。
此外,CPU数量越多,跨CPU访问内存的距离可能会越远,速度会越差,所以NUMA结构的性能并不能随CPU数量的增加而线性增长。
下图是4个CPU组成NUMA结构,总共32核,总共分配32G内存,每颗CPU分配8G内存作为自己的本地内存。