Python的线程
从网上down下Norman Matloff and Francis Hsu的Tutorial on Threads Programming with Python。
文档写得不错,不过我没有很仔细地看,主要原因是因为对Py的线程并不陌生。真正让我感兴趣的是,这篇文档对Py线程机制的实现做了点介绍。下面就是我的总结,也不知道对不对。
Py的程序是通过Py的解释器运行的,所以程序员写的多线程Py代码究竟会怎么运行,要取决于解释器。Py的解释器是一个单进程的程序。不过单进程也没有关系,Java的解释器就是单进程的,但是它可以用多线程的方式解释Java的多线程程序,因此当你发现Java程序运行得很慢的时候,或许可以用加CPU的办法来解决问题。但是我们的Py比较弱。它只能以单线程的方式运行。下面是Py Manual关于GIL的描述。
In order to support multi-threaded Python programs, there's a global lock that must be held by the current thread before it can safely access Python objects.
-- Py 2.5 Manual, Python/C API Reference Manual 8.1 Thread State and the Global Interpreter Lock
外部的C程序如果要调用Py的解释器,必须先拿到它的GIL。换句话说,就是Py的解释器在解释Py的源代码的时候,只有一条流水线,因此你得先拿到钥匙才能往里面灌水。
这是流水线一头的情形。下面是流水线的另一头。
我们都知道,Py的多线程能提升I/O性能。但这和Py的单线程相矛盾。比方说有一个线程发出了I/O指令,Py解释器交给了底层的OS。I/O操作一般都是block的,因此在OS返回结果之前,整个进程都是block的。这么一来,多线程根本就不可能提升I/O性能了。
我没有看过Py的源代码,但是这里应该猜得不会太离谱。Py解释器在碰到I/O指令的时候,一定是生成一个线程,然后让这个线程去等OS的返回。它自己的解释引擎肯定是不会去等OS的。
这么以来,Py的多线程其实是一个混合实现。解释引擎是单线程的,但是它会以多线程的方式请求OS的服务。因此多线程的I/O能提升性能,但是多加CPU却没用。
很多脚本引擎的多线程实现都是这样。好像Ruby的也是。