从计算机硬件角度:
计算机的核心是CPU,所有计算任务都由CPU负责。
单个CPU核心,在一个CPU时间片里,只能执行一个程序任务。
台式机 intel i5 处理器 四核四线程:
四个CPU核心,每个核心有一个逻辑处理器
同时可以处理四个任务。
台式机 intel i7 处理器 四核八线程 (intel 超线程技术)
四个CPU核心,每个核心有两个逻辑处理器,
同时可以处理八个任务。
注意:CPU的x核x线程,和操作系统调度的线程,不是一回事。
从操作系统角度:
进程和线程,都是CPU执行任务的执行单元。
进程:表示一个程序的执行活动(上下文管理,打开、读写、关闭)
线程:表示进程工作时的最小调度单位(执行功能a,执行功能b...)
一个程序至少有一个进程,一个进程内至少有一个线程
并行:
执行单元CPU == 执行的任务
任务1: ----------
任务2: ----------
任务3: ----------
并发:
执行单元CPU < 执行的任务
一个CPU、3个任务
任务1:------ -------
任务2: ------ ------
任务3: ------
多进程 和 多线程:
表示一个程序可以同时执行多个任务,进程和线程调度都是有操作系统完成。
多进程:进程和进程之间不共享任何状态,每个进程都有自己独立的内存空间。
如果进程之间做数据通讯或切换,操作系统开销很大。
多线程:同一个进程下的多线程共享,该进程的内存空间,
如果线程之间做数据通讯和切换,操作系统开销很小。
共享意味着竞争,可能会带来数据的安全隐患,所以有了"互斥锁"。
互斥锁:一种安全有序的让多个线程访问进程内存空间的机制,避免产生数据安全问题。
解释型语言:利用解释器按行执行代码,程序执行后做语法检查。
编译型语言:利用编译器编译代码生成可执行文件,程序执行前做语法检查。
GIL 全局解释器锁: 同一时刻只能有一个线程在工作。
Python只有一个GIL,当线程需要执行任务时必须获取GIL,那么其他线程就处理等待状态。
坏处:不能充分利用CPU多核资源。
好处:直接从根本上杜绝了多线程访问内存空间的安全问题。
当程序执行一个IO阻塞的函数时,解释器会释放GIL。
如果程序中没有IO阻塞操作,解释器会每隔100次操作,会释放GIL,让其他线程尝试工作。
sys.getcheckinterval()
多进程:密集CPU任务(大量的并行计算),可以充分使用多核CPU的资源。
multiprocessing
缺点:进程之间通信和切换成本高,如果需要大量数据通信和切换的场景,不适合用多进程。
多线程:密集I/O任务(网卡IO、磁盘IO、数据库IO)
threading、 multiprocessing.dummy
优点:线程之间通信成本和切换开销极小。
缺点:在Python里一个CPU时间片只能执行一个线程,不能充分利用多核CPU的资源。
协程:在单线程上执行多个任务,任务调度由程序员控制,基于用户管理,不受操作系统控制。
所以没有线程,进程的切换开销,也不需要处理互斥锁。
通过代码逻辑,不停的切换需要指定的函数。
gevent
from gevent import monkey
monkey.patch_all()
给Python底层的网络库(socket、select)打个补丁,在处理网络IO任务时,可以按异步非阻塞方式执行。
优点:不经过操作系统调度,所以执行效率高。
缺点:因为是单线程执行,所以处理CPU密集任务、密集本地IO 不合适。
多进程:密集CPU任务
多线程:密集IO任务
协程:密集网络IO任务
主线程结束后,非守护线程不会结束,守护线程会结束,Python默认创建的线程都是非守护线程。