Python多线程随手记
内容来自于Python并发编程实战
有哪些程序提速的方法?
单线程串行
普通脚本就是单线程串行。
多线程并发
CPU和IO同时工作,对应Threading。CPU不用等带IO。
多CPU并行(多进程)
由于当前PC中处理器都包含多核心,利用多个核心,多进程并行执行任务,对应MultiProcessing。利用多核CPU的能力,真正的并行执行任务。
多机器并行
大数据时间通常使用多个PC进行任务,对应Hadoop/Hive/Spark等。
Python对并发编程的支持
- 多线程、多进程;
- asycio,在单线程利用CPU和IO同时执行的原理,实现函数异步执行;
- Lock可以对资源加锁,防止冲突访问;
- 使用Queue实现不同线程/进程之间的数据通信,实现生产者-消费者模式;
- 使用线程池Pool、进程池Pool,简化线程、进程的任务提交、等待结束、获取结果;
- 使用subprocess启动外部程序的进程,并进行输入输出交互;
Python并发编程的三种方式
线程、进程、协程之间有层级关系。一个进程中可以包含和启动很多个线程,一个线程可以启动很多个协程。
预备知识
CPU密集型计算(CPU-Bound)
CPU-Bound指在执行任务过程中会受到CPU的限制,也叫做计算密集型,I/O在很短的时间就可以完成,CPU需要大量的计算和处理,特点就是CPU占用率相当高。
比如:压缩解压、加密解密、正则表达式搜索。
IO密集型计算(I/O-Bound)
I/O-Bound指在执行任务过程中会受到I/O的限制,系统运作大部分的状况时CPU在等I/O(硬盘/内存)的读/写操作,CPU占用率较低。
比如:文件处理程序、网络爬虫程序、读写数据库程序。
多线程Thread
多进程通常通过threading库实现,使用于I/O密集型计算、同时运行的任务数目要求不多。
- 优点:
相比进程,更轻量、占用资源更少。 - 缺点:
相比进程:多线程只能并发执行,不能利用多CPU(GIL);
相比协程:启动数目有限制,占用内存资源,有线程切换开销。
多进程Process
多进程通常通过multiprocessing库实现,适用于CPU密集型计算。
- 优点:
可以利用多核CPU并行计算 - 缺点:
占用资源最多、可启动数目受限于处理器核心数量,比线程要少。
多协程Coroutine
多协程通常通过asyncio库实现,使用I/O密集型计算、需要超多任务运行、有现成库支持的场景。
- 优点:
内存开销最少、启动数量最多。 - 缺点:
支持库有限制,很多库都不支持协程技术(requests VS aiohttp)、代码实现复杂。
requests库就不支持协程,如果需要使用到多协程,只能使用aiohttp库。
全局解释器锁GIL
Python速度慢的原因
导致Python速度慢的原因有两个:
- 执行过程边解释边执行;
比如C++程序在编写完成后会先编译成机器码,机器执行机器码的速度非常快,但Python执行的就是源码,需要边翻译成机器码,边执行。 - Python是动态类型语言
Python中的变量可以是任意类型,可以随意的从“数字”切换到“字符串”,这导致了在执行过程中Python需要随时检查变量的类型,从而影响程序执行速度。 - GIL
由于GIL的存在导致Python无法利用多核CPU并发执行程序。
GIL是什么
全局解释器锁(Global Interpreter Lock,GIL),是计算机程序涉及语言解释器用于同步线程的一种机制,它使得任何时刻仅有一个线程在执行。即便在多核心处理器上,使用GIL的解释器也只允许同一时间执行一个线程。
GIL存在理由
Python设计初期,为了规避并发问题引入GIL,后来想去除去不掉了。
GIL存在的目的是为了解决多线程之间数据完整性和状态同步的问题。Python中对象的管理,是使用引用计数器进行的,引用数量为0则释放对象。
举个栗子:
假设存在线程A和线程B都引用对象obj,obj.ref_num=2,线程A和线程B都想撤销对obj的引用。
线程A先撤销引用,obj.ref_num=1,此时发生多线程调度切换,切换到线程B。线程B撤销obj的引用,obj.ref_num=0,又由于Python通过引用数管理对象,obj.ref_num=0后内存中就删除了变量obj的相关内容,此时发生多线程调度切换,切换回A时可能就会对其他应用程序造成影响。
如何避免GIL带来的限制
- threading机制依然可用
因为在I/O期间,线程会释放GIL,实现CPU和IO的并行,因此多线程用于IO密集型计算依然可以大幅度提升速度,但多线程用于CPU密集型计算时,只会拖慢速度。 - 使用multiprocessing实现并行计算
为应对GIL的问题,Python提供了multiprocessing模块,用于多计算机制实现真正的并行计算。