进程与线程
本文写于 2020 年 11 月 21 日
进程(process)是什么?
在我们使用 Windows 或者是 MacOS 等操作系统时,会下载很多「应用程序」。例如“英雄联盟.exe”就是一个程序。
程序进程,两个长得有些相似,但程序并不是进程。只是在我们启动「程序」的时候,操作系统会开启一个「进程」。
这一点很多不懂编程的用户都应该了解,因为打开 Windows 的资源管理器,就会有进程窗口。这个窗口会显示他的 CPU、内存、网络、电源占用等等信息。
进程的定义
进程,是指计算机中已运行的程序。但是进程的定义比较多,也就是说并不太清晰。
例如在面向进程设计的系统中,进程是程序的基本执行实体;在面向线程设计的系统中,进程本身不是基本运行单位,而是线程的容器。
如果你读不懂上面一段话,我们后面讲线程会再次说,目前可以这么认为:
进程就是程序的执行实例,程序在 CPU 执行时的活动就叫进程。如果我们开启了两遍程序,那就开启了两个进程;将一个程序开了一遍,一个程序开了两遍,就是三个进程。
进程的特点
进程是可以创建另一个进程的。
比如当我们在浏览器打开多个窗口的时候,就能明显的观察到线程数量的增多。
为什么需要进程?
这就要从 CPU 的特点讲起了。
对于单核 CPU 而言,在某一刻就只能做一件事情。可即使我们使用单核的 CPU,我们一样可以开很多的软件呀(虽然很卡),这是为什么呢?
因为 CPU 是阿甘(详见《码农翻身》),他跑的速度很快,而且一直在跑,所以他可以干一会儿 A 事情,再干一会儿 B 事情——由于他的速度实在是太快了,人类无法分辨,所以就让我们感觉到“可以同时干多件事儿”。
因此当我们再计算机上并发执行多程序的时候,操作系统会帮我们新建多个进程,每个进程都会出现 「执行」-「暂停」-「执行」 的规律,并且多个进程之间会出现抢夺资源的现象。
例子:新建一个 Chrome 进程
当我们启动 Chrome 时,操作系统会为我们创建一个进程,该进程会立即进入 「非运行」 状态,直到操作系统告诉(分派)该进程,“我空了,你来运行吧”,该进程才会进入 「运行」 状态。
因为存在多个进程,所以进程的执行需要排队:进入进程队列-等待分派-CPU 执行-暂停-再次进入进程队列。
进程会在运行与非运行两个状态之间不断切换,直到你退出了该进程。也就是不断的在被 「暂停」与「分派」。
进程的阻塞
进程是由 CPU 执行的,但是如果我们有一个读取硬盘文件的进程,他根本不使用 CPU,而硬盘的速度又巨慢无比(与 CPU 相比),就会让 CPU 在那里干等着——这就是进程阻塞。该进程既不消耗资源,还不空出队列,堵住了后面的需要执行的进程。
具体点讲就是:
- 在进程队列中,大家都在处于非运行态等待执行;
- 其中 A 类在等待 CPU 的资源,B 类在等待 I/O 或者网络请求之类的需要较长时间完成的事情;
- 这时候如果 CPU 分配给了 B,B 还是在等待 I/O 或者网络请求,根本不用 CPU,就叫做进程阻塞。
我们刚刚说的「非运行」状态这时就可以变成两个状态了: 「就绪」与「阻塞」。
如果一个进程没有 I/O 之类的操作,在运行一段时间之后就会超时,重新进入就绪状态;如果你需要 I/O 之类操作,就会进入阻塞状态,时间完成后才能进入就绪状态,才能被再次分派给 CPU。
线程(Thread)是什么?
在早期的操作系统中,我们是面向进程设计设计的操作系统,进程是程序的基本执行实体。
但是后来我们改为了面向线程设计的系统,进程本身他不是基本运行单位了,变成了线程的容器。
即:线程 < 线程。
因为进程虽然好,可是太耗费资源了。我们创建、切换、销毁进程都需要分配实体资源,也就是 CPU 必须参与这些步骤。
有了线程之后,进程只作为容器,里面的具体操作落到了线程身上,操作系统就不需要操心了。
线程的概念
- 线程是现在操作系统 CPU 调度和执行的最小单元;
- 一个进程中至少有一个或以上的线程;
- 一个进程中的线程共享该进程的所有资源;
- 进程中的第一个线程叫做初始化线程;
- 线程的调度可以有操作系统负责,也可以由用户负责。
这个时候我们就产生了一个疑问:我到底是用子进程还是线程呢?
线程的优先级当然更高,除非我们需要单独分配一些资源,例如浏览器的每个页面。
(完)