浅析python中的GIL锁和协程

GIL锁

GIL锁Global Interpreter Lock(全局解释器锁)

是基于c语言的cpython下的多线程的机制。

解决多线下程造成的数据完整性和同步的问题。

也就是说同一时间,只有一个线程可以执行。

当前线程遇到I/O,或者字节码执行100行(python2,python3中使用计时器时间到达阈值释放GIL),才会释放GIL锁。

只有当GIL锁释放后,才会切换其他线程运行。

在切换线程的过程中也会耗费资源。

多核多线程

多核多线程的情况下,由于GIL锁的,只能一个cpu执行当前任务。

切换后也只有一个cpu在执行任务,一定时间后GIL释放机制,又会切换cpu。

切换造成资源浪费。而一个cpu执行的过程中,其他cpu被闲置,也是浪费资源。

多线程在计算密集型

在计算密集型的情况下,不建议使用多线程。计算过程中,单线程一直在同一任务下执行,执行100行字节码(python2),没有执行完,切换了线程的,切换过程也会增加损耗,多线程会比单线程,执行更长的时间。

多线程在I/O密集型

在I/O密集型的情况下,推荐使用多线程。单线程与I/O会阻塞等待,直到I/O结束,继续执行。多线程遇到I/O,会切换执行下一线程任务,更合理的使用了cpu资源,提升执行效率。

协程

在使用多线程的时,每个线程遇到IO的情况下,等待IO结束期间被闲置,这种情况被视为一种资源浪费。而协程不会也这种情况,协程可以使一个线程切换任务,使一个线程分片执行任务。

  1. 协程基于异步IO

    单纯协程只能人为的指定在什么情况下切换。不过协程和异步IO结合使用,可以达到遇到IO就切换的效果。异步IO的常用模块gevent,gevnet里面使用协程的方法是greenlet。

  2. 协程基于事件循环(IO多路复用)

    I/O多路复用,通过一种机制,可以监视多个文件描述符,一旦描述符就绪(读就绪和写就绪),能通知程序进行相应的读写操作。其中Socket模块的setBlocking(Flase)起到了遇到IO不等待(非阻塞)的继续执行任务的作用 。selector起到了接收回调信号的返回结果,通知程序做对应处理的作用。Twisted和Tornado都是基于事件循环的方式处理。