cpu,核,进程与线程

时间:2023-03-08 16:44:46

多进程与多线程


一张图,先来回顾一下并行,并发,串行:

cpu,核,进程与线程

一、多核多线程

当我们要去买一台新电脑时,我们一般都会比较多台电脑的配置,而其中一项关键配置就是几核几线程。一般现在很多电脑都是4核8线程,甚至是8核16线程的。那么这里的4核8线程是什么意思呢?和cpu是什么关系呢?

1. 查看电脑核心数

开始菜单-->运行-->cmd-->输入wmic-->输入cpu get* 并将底部滚动条拖拽到如下图所示位置

cpu,核,进程与线程

cpu,核,进程与线程

NumberOfCores:2(核数为2)

NumberOfLogicalProcessors:4(逻辑线程数为4)

即这就是所谓的2核4线程

2. cpu的超线程技术

以上我们可以看到我的电脑是2核4线程的,但我的电脑只有一个处理器(cpu)芯片,即2个核是指在一个cpu中集成了两个完整的计算引擎(内核)。

多核

仅仅提高单核芯片的速度会遇到很多问题,英特尔工程师转而“横向发展”,提高计算机性能。线程应用能够充分利用多个内核,在同样的时间内完成更多的任务,大大提高cpu的性能。多核处理器是单枚芯片,可以插入一个处理器卡槽内,操作系统会利用相关资源将单枚芯片中的多个执行内核分立为多个处理器。

多线程(不同于程序中的多线程)

事实上单个执行内核的性能并没有被充分利用,因此工程师们又采用了另一个思路去提高cpu性能,即让单个执行内核可以同时执行多重线程,从而进一步提高cpu性能,这就是所谓的超线程技术

虽然单线程核心每秒能处理成千上万条指令,但任一时刻,内核只能对一条线程进行操作,而其实这个内核还有很多性能没有被利用到,空闲着。超线程技术就是在一个执行内核上同时执行两个线程,两个线程共享这一个内核的资源。理论上来说就像两个独立的执行内核分别同时执行两个线程一样,但其实并不是这样。当两个线程同时需要同一个内核资源时,其中一个线程必须等待另一个线程使用完后释放资源,才能继续执行。所以超线程性能并不等于两个执行内核的性能。这里的多线程只是逻辑上的多线程,并不是真正意义上独立的多线程。

二、多进程与多线程

1. 多任务

思考这样一个场景,你正在使用电脑一边播放音乐,一边浏览网页,同时还在聊QQ。此时电脑上至少有三个任务在“同时”运行,其实还有许多任务在后台执行只是你看不到罢了。任务数远大于cpu核心数,所以这里的多任务同时运行往往指的是并发执行,而不是并行执行。大量任务在cpu的多个内核上交替切换执行,但由于cpu执行速度太快,以至于我们感觉不到任务的切换,让人感觉所有任务都是在同时运行着。事实上,如果cpu是2核2进程的,则同一时刻只能有2个任务同时执行;如果cpu是2核4进程的,理论上同一时刻能够同时执行4个任务,实际上往往并不会达到4个任务并行执行,原因上节已经讲述在此不再赘述。

2. 多进程与多线程

对于操作系统来说,一个任务就是一个进程。比如打开一个world就是一个进程,打开两个world就是两个进程,打开浏览器也是一个进程。但有些进程不单单只完成一件事,比如在浏览器上看电影时,浏览器既要播放视频又要播放音频还要播放字幕等,这样在一个进程内就要做多件事,这多个子任务实际上就是进程中的线程。

由于每个进程至少要干一件事,多以每个进程至少有一个线程。多个线程的执行方式和多进程执行方式一样,是由操作系统在多个线程间切换执行的,切换速度极快导致我们感觉多个线程是同时执行的,事实上,现代操作系统都将线程作为最小的调度单位,而将进程作为资源分配的最小单位。一个进程内的多个线程是可以并行运行在多个核上的,但这也并不是一定的,比如python的线程模型并不支持并行运行在多个核上。

3. 多任务与多进程,多线程的关系

结合以上两节我们可以总结出同时执行多个任务的3种解决方案:

  • 多进程模式:开启多个进程,每个进程开启一个线程,每个线程完成一件事,多个进程就完成多件事
  • 多线程模式:开启一个进程,一个进程里开启多个线程,每个线程完成一件事,1个进程就完成多件事
  • 多进程和多线程组合模式:开启多个进程,每个进程内开启多个线程,每个线程完成一件事,多个进程就完成多件事

以上三个解决方案中,方案三实现起来很复杂,需要解决的问题很多,使用的较少。而方案二,看似很好,一个进程就能完成多件事,那我们是不是可以将多个任务都在一个进程内的多个线程上完成呢?事实上,一个进程内不能无限制地开启很多个线程,当线程数量超过一定上限时,进程内线程间的切换,上下文环境的保存恢复需要占用大量时间,导致cpu性能下降。

4. 多进程与多线程的关系及优缺点

进程与线程间的关系:

  • 一个进程至少有一个线程,可以有多个线程,但不可有过多的线程,否则性能下降
  • 一个进程内的多个线程可以并行运行在多核多线程的处理器上
  • 一个线程只属于一个进程,不可能两个或多个进程拥有同一个线程
  • 进程是操作系统资源分配的最小单位,一个进程内的多个线程共享该进程的资源
  • 线程是操作系统调度的最小单位,即cpu分配给线程,真正在cpu上执行的是线程

多进程的优缺点

优点:每个进程间是相互独立的,一个进程的崩溃不会影响到其他进程的执行,稳定性高。

缺点:进程创建,调度等开销大。

多线程优缺点

优点:多线程直接共享进程资源,创建调度等开销小。

缺点:正是由于多线程共享进程资源导致任何一个线程挂掉都可能导致整个进程奔溃。

不管是多进程还是多线程,如果数量一多,效率就会下降,因为系统调度会占用大量cpu时间。

三、python中的多线程

前面说到一个进程内的多个线程可以并行运行在多个cpu内核上,但Python程序的线程不能运行在多个内核中,所有线程都只能在一个cpu内核中交替执行。因为Python的线程虽然是真正的线程,但解释器执行代码时,有一个GIL(Global interpreter Lock)锁,python线程在执行前必须先获得GIL锁,而一个进程中只有唯一的一个GIL锁,导致python线程不能实现并行。即使是100个线程在100个核的cpu上执行,真正能用到的也只有一个核。python中虽然可以使用多线程,但无法利用多核的性能。

解决方案:

  • 重写python的解释器,实现一个不带GIL锁的解释器
  • 对线程并行要求较高的程序,核心代码使用C,C++或java来编写
  • 使用多进程来替代多线程,充分利用多核的性能。多个python进程各自有自己的GIL锁,互不影响。

四、IO密集型 vs 计算密集型

是否需要开启多进程,多线程?开启多少个进程,线程?这与任务的类型有关。我们可以将任务分成IO密集型和计算密集型两种。

IO密集型任务:IO密集型任务是指任务中更多的是等待IO请求,比如磁盘IO或网络IO,这类任务的特点是cpu消耗的少,任务的大部分时间是在等待IO,因为IO的速度远低于cpu的速度。这类任务,应开启的更多数量的进程,线程,cpu的运行效率越高。一个任务阻塞时可以切换到其他就绪任务,提高cpu利用率。常见的大部分任务都是IO密集型任务,比如web应用。

计算密集型:这类任务主要为复杂的逻辑判断和复杂的运算,需要进行大量的计算,消耗大量cpu资源。这类任务不能开启太多,否则任务切换时会占用太多cpu时间,降低cpu性能。这类任务的执行要达到cpu的最高效率,任务数不能大于cpu的核心数,这样不会将cpu时间浪费在切换任务上,而将所有时间用在计算上。