并发编程
进程:操作系统分配资源的基本单位。多进程属于并行:在同一时刻同时处理多个任务。
线程:操作系统调度资源的最小单位。多线程属于并发:在一段时间内交替处理多个任务。
协程:你可以把它想象成在一个线程内部,多个任务之间进行协作和切换。协程属于并发:在一段时间内交替处理多个任务。
多进程、多线程的出现,核心目的是为了最大限度地利用中央处理器(CPU)这一关键硬件资源。
多进程通过调动更多的CPU核心,从而提高程序的执行效率。
那为什么多线程没有使用更多的资源,只是交替处理多个任务,就能更快?
以一个常见的爬虫任务为例,其工作流程可以分为两个主要步骤:
- CPU指挥网卡发送网络请求,这一过程往往需要等待远程服务器响应(例如,网络通信耗时1秒)。
- CPU指挥磁盘将接收到的数据写入磁盘,完成持久化存储(例如,磁盘耗时19秒)。
-
单线程模式:在单线程下处理10个网址,程序必须顺序执行。当第一个网址的网络请求发送后,程序会进入等待状态,直到数据完全写入磁盘(总耗时20秒)后,才能开始处理第二个网址。因此,处理10个网址的总耗时将是 秒,即200秒。CPU长时间闲置。
-
多线程模式:多线程则能显著提高效率。当第一个线程发出网络请求后,CPU不再闲置等待,而是立即切换到第二个线程,发起新的网络请求。这样,CPU可以在等待I/O操作(如网络响应和磁盘写入)完成的同时,处理其他任务。通过这种方式,CPU最大程度不空闲,指挥多个网络请求和磁盘写入操作并行进行,从而大幅缩短总体的完成时间。
这个切换过程称之为上下文切换,会产生一定的开销,由操作系统自动完成,操作系统不一定在最合理的时间点进行上下文切换。
因此为了进一步提高效率,我们使用协程来完成这个任务。在协程中,程序员在代码中编 写await关键字来完成主动上下文切换。
📄️ asyncio
asyncio 模块
📄️ concurrent
Python 目前拥有强大的原语来构建多线程和多进程应用,但并行化简单作需要大量工作,比如显式启动进程/线程、构建工作/结果队列,以及等待完成或其他终止条件(如失败、超时)。当每个组件都发明自己的并行执行策略时,设计具有全局进程/线程限制的应用程序也变得困难。
📄️ contextvars 🔨
📄️ multiprocessing
进程是系统独立安排和分配系统资源(CPU、内存)的基本单位,操作系统以进程为单位分配存储空间,操作系统管理所有进程的执行,为它们合理的分配资源。
📄️ queue 🔨
📄️ threading
线程是系统调度资源的最小单位(CPU 通过计时器来切换线程)