《Python源码剖析》读书笔记:多线程

(如无特别注明,以下笔记都是基于Linux平台)

  • GIL覆盖面不只是Python的解释器,还包括Python的C API
  • Python线程根据”已执行指令数”来切换线程,在Python 2.5+,这个阈值是100
>>> import sys
>>> sys.getcheckinterval()
100

但有些字节码指令执行并不会增加这个计数,因此线程切换时已执行指令数可能会比这个略多
** 当字节码执行之后通过goto转移到fast_next_opcode,这时不会更新计数器
** 线程通过阻塞调度,并不会重置计数器

  • GIL并不是随着解释器启动而创建的,只有用户第一次使用thread的时候创建。
  • 在不同平台上GIL使用不同的实现,在Linux使用信号量。
  • 创建线程使用pthread库,Python线程是使用系统原生线程。
  • 子线程创建后马上申请GIL
  • PyThreadState保存了这个线程的上下文信息
  • 当一个活动线程挂起后,调度到哪个线程由操作系统线程调度决定。当前活动线程挂起前,会释放GIL

  • Python线程调度有两种方式,一种是标准调度,另一种是阻塞调度。
    ** 标准调度是当前线程已执行指令数大于100时主动释放GIL,让其他线程有机会运行。
    ** 阻塞调度是当前线程执行到阻塞的系统调用(例如time.sleep)之前,释放GIL,让其他线程有机会运行。

  • thread模块提供基础的Lock对象,默认使用信号量,如果在信号量有问题的情况下,使用pthread_lock

  • 当前线程对Lock对象加锁前,先释放GIL,获得锁后再获取GIL。(Threadmodule.c:38)
  • threading模块是Python写成的。里面的RLock/Condition/Semaphore/Event锁对象都是基于thread.Lock
  • threading模块的Thread启动分两步,第一步使用thread.start_new_thread创建原生线程,原生线程执行__bootstrap函数,此时线程状态为创建中,放入_limbo字典;第二步在__bootstrap函数中将自己放到_active字典,以线程ID为key,然后执行run函数

PS: 求购正版《Python源码剖析》,或求提供陈儒联系方式,谢谢!