Python的代码执行由 Python虚拟机(也叫解释器主循环,CPython版本)来控制,Python在设计之初就考虑到在解释器的主循环中,同时只有一个线程在运行。即每一个CPU在任意时刻只有一个线程在解释器中运行。对 Python虚拟机访问的控制由全局解释锁GIL控制,正是这个锁来控制同一时刻只有一个线程可以运行。——在单核CPU下的多线程其实都只是并发,不是并行 。python
并发与并行区别网络
并发和并行的意义多线程
并发和并行均可以处理“多任务”,两者的主要区别在因而否是“同时进行”多个的任务。可是涉及到任务分解(有前后依赖耦合度高的任务没法作到并行)、任务运行(可能要考虑互斥、锁、共享等)、结果合并。并发
在Python多线程下,每一个线程的执行方式,以下:函数
在Python2中,在解释器解释执行任何 Python 代码时,都须要先得到这把锁才行(同一时间只会有一个得到了 GIL 的线程在跑,其它的线程都处于等待状态等着 GIL 的释放),在遇到 I/O 操做时会释放这把锁。若是是纯计算的程序,没有 I/O 操做,解释器会每隔 100 次操做就释放这把锁,让别的线程有机会执行(这个次数能够经过 sys.setcheckinterval 来调整)也正是这种设定,是的多线程的CPU密集型计算很是鸡肋,下面会讲到为什么如此。性能
而在python3中,GIL不使用ticks计数(100次,释放GIL),改成使用计时器(执行时间达到15ms阈值后,当前线程释放 GIL),使得执行计算的次数更多,释放次数减小,这样对CPU密集型程序更加友好,但依然没有解决GIL致使的同一时间只能执行一个线程的问题,因此效率依然不尽如人意。测试
CPU密集型(各类循环处理、计数等等),在这种状况下,ticks计数很快就会达到阈值,而后触发GIL的释放与再竞争(多个线程来回切换是须要消耗资源的),因此python下的多线程对 CPU密集型代码并不友好,会触发至关频繁的线程切换。线程
IO密集型(文件处理、网络爬虫等),多线程可以有效提高效率(单线程下有IO操做会进行IO 等待,形成没必要要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,能够不浪费 CPU的资源,从而能提高程序执行效率,一个线程得到GIL发送消息,而后等待返回消息(阻塞),Python此时释放GIL, 其余线程获得GIL发送消息,而后一样等待返回消息(阻塞)......,这样保证了IO传输过程时间的合理利用,减小了IO等待形成的资源浪费,提升IO传输效率)。因此python的多线程对IO密集型代码比较友好。设计
I/O密集型使用多线程并发执行提升效率、计算密集型使用多进程(multiprocessing )并行执行提升效率。一般程序既包含IO操做又包含计算操做,那么这种状况下,在开始并发任务以前,能够先进行测试,测试多线程、多进程哪一个效率高就是用哪一种方式。协程
请注意:多核多线程比单核多线程更差,多核多进程下,CPU1释放GIL后,其余CPU上的线程都会进行竞争,但GIL可能会立刻又被CPU1拿到,CPU2释放GIL后……,致使其余几个CPU上被唤醒后的线程会醒着等待到切换时间后又进入待调度状态,这样会形成线程颠簸(thrashing),致使效率更低。
多线程下的CPU密集型计算也不是无药可医,能够利用ctypes绕过GIL,ctypes可使py直接调用任意的C动态库的导出函数。所要作的只是把关键部分用 C/C++ 写成 Python 扩展。并且,ctypes会在调用C函数前释放GIL。
同时,能够了解下协程,又称微线程。
协程最大的优点就是协程极高的执行效率。由于子程序切换不是线程切换,而是由程序自身控制,所以,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优点就越明显。
第二大优点就是不须要多线程的锁机制,由于只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只须要判断状态就行了,因此执行效率比多线程高不少。
由于协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可得到极高的性能。
转自
Python多进程和多线程是鸡肋嘛? https://www.toutiao.com/a6738231652184490247/