《老鸟python 系列》视频上线了,全网稀缺资源,涵盖python人工智能教程,爬虫教程,web教程,数据分析教程以及界面库和服务器教程,以及各个方向的主流实用项目,手把手带你从零开始进阶高手之路!点击 链接 查看详情




第十五章:多进程、多线程和协程

阅读:214364971    分享到

进程和线程是学习任何编程语言都需要了解的,协程也在最近几年流行起来,特别是在 Python 语言中被广泛的使用。因为进程和线程都是概念性的,而多进程和多线程才被应用到编程中,本章我们主要学习多进程、多线程和协程概念和应用。

我们在学习多进程,多线程和协程之前,先了解下进程,线程和协程的定义。

概念

进程: 进程是指在系统中正在运行的一个应用程序。程序是指令、数据及其组织形式的描述,进程是程序的实体。程序一旦运行就是进程;进程是线程的容器,进程——资源分配的最小单位。

线程:线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

协程:协程,又称微线程,纤程。英文名 Coroutine。一句话说明什么是协程:协程是一种用户态的轻量级线程。

多进程、多线程和协程

在了解多进程、多线程和协程之前,首先我们要先了解“多任务”。

“多任务”就是你计算机上的操作系统可以同时执行多个任务。举个栗子,比如你在电脑上一边用着某神器看着心爱的小片,一边用 QQ 和女票聊天,一边在用 Pycharm 撸着代码,这就是多任务,至少同时有 3 个任务正在运行。当然,还有很多任务悄悄地在后台同时运行着,比如操作系统的服务等等,只是桌面上没有显示而已。

当然理论上来说,计算机如果要同时执行“多任务”,必须要有多个 CPU,因为一个 CPU 就如同是一个人,一个人“同时”只能做一件事,同样一个 CPU “同时”只能执行一个任务。

由于 CPU 执行代码都是顺序执行的,那么,早期的单核 CPU 是怎么执行多任务的呢?

答案就是操作系统给操作系统分配时间片,让 CPU 轮流执行各个任务,任务 1 执行 0.001 秒,切换到任务 2,任务 2 执行 0.001 秒,再切换到任务 3,执行 0.001 秒……这样反复执行下去。表面上看,每个任务都是交替执行的,但是,由于执行每个任务的时间片很短,我们感觉就像所有任务都在同时执行一样。

当然多个 CPU 执行“多任务”(要保证每个 CPU 同时只能执行一个任务),我们叫做并行。而用单个 CPU 以时间片切换的方式去执行“多任务”,我们叫做并发。当然并行和并发都是“多任务”,虽然并发不是同时去执行,但是给我们的感觉上来说是同时的,因为切换的太快了,对我们感觉上来说是同时执行的。

虽然现在来说我们的电脑基本上都是多 CPU,但是,由于任务数量远远多于 CPU 的核心数量,所以,即时你是多个 CPU,操作系统也会自动把很多任务轮流调度到每个核心上执行。也就是说你多个 CPU 也不能保证并行执行“多任务”,而是经常用到并发去执行“多任务”。

对于操作系统来说,一个任务就是一个进程(Process),比如打开一个播放器就是启动一个播放器进程,打开一个 WORD 软件就启动了一个 WORD 进程,打开两个 WORD 就启动了两个 WORD 进程,打开一个播放器就启动了一个播放器进程。

有些进程还不止同时干一件事,比如 Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)。

由于每个进程至少要干一件事,所以,一个进程至少有一个线程。当然,像 Word 这种复杂的进程可以有多个线程,多个线程可以同时执行,多线程的执行方式和多进程是一样的,也是由操作系统在多个线程之间快速切换,让每个线程都短暂地交替运行,看起来就像同时执行一样。当然,真正地同时执行多线程需要多核 CPU 才可能实现。

我们前面编写的所有的 Python 程序,都是执行单任务的进程,也就是只有一个线程。如果我们要同时执行多个任务怎么办?

有三种解决方案:

一种是启动多个进程,每个进程虽然只有一个线程,但多个进程可以一块执行多个任务。

还有一种方法是启动一个进程,在一个进程内启动多个线程,这样,多个线程也可以一块执行多个任务。

当然还有第三种方法,就是我们自己写的程序在逻辑上对每一个任务进行轮询,但要保证你的每一个任务都是非阻塞的,这样你才可以给每一个任务分配时间片,也就是说每一个任务每次执行都是占用 CPU 很少的时间,你马上就切换到另一个任务,这和模拟操作系统分配 CPU 时间片的方式进行轮询是一样的,这种方式叫做单线程异步并发,这是目前“多任务”编程开发的主流,比如 nginx,tornado,nodejs等等主流多并发框架,他们都是采用单线程异步轮询的方式实现并发。恰恰我们的 Python 中引入的协程亦是如此。

总结一下就是,多任务的实现有 3 种方式:

  • 多进程模式。
  • 多线程模式。
  • 非阻塞单线程异步轮询(比如 Python 中有自带的协程)。

同时执行多个任务通常各个任务之间并不是没有关联的,而是需要相互通信和协调,有时,任务 1 必须暂停等待任务 2 完成后才能继续执行,有时,任务 3 和任务 4 又不能同时执行,所以,多进程和多线程的程序的复杂度要远远高于我们前面写的单进程单线程的程序。

因为复杂度高,调试困难,所以,不是迫不得已,我们也不想编写多任务。但是,有很多时候,没有多任务还真不行。想想在电脑上看电影,就必须由一个线程播放视频,另一个线程播放音频,否则,单线程实现的话就只能先把视频播放完再播放音频,或者先把音频播放完再播放视频,这显然是不行的。

Python 既支持多进程,又支持多线程,还支持协程,接下来,本章我们会学习如何编写这三种多任务程序。


如果以上内容对您有帮助,请老板用微信扫一下赞赏码,赞赏后加微信号 birdpython 领取免费视频。


登录后评论

user_image
青芒果0527
2020年4月28日 04:07 回复

请教个问题。协程可以进入上一次离开时所处逻辑流的位置,线程可以么


user_image
陈硕
2019年3月30日 11:31 回复

非常好,解释的简洁明了!这种知识相互对比才能更好的理解[赞]