线程和Python
本节主要记录如何在 Python 中使用线程,其中包括全局解释器锁对线程的限制和对应的学习脚本。
全局解释器锁
Python 代码的执行是由 Python 虚拟机(又叫解释器主循环)进行控制的。
-
对 Python 虚拟机的访问是由全局解释器锁(GIL)控制的。步骤为:
-
设置 GIL;
切换进一个线程去运行;
-
执行下面操作之一:
a. 指定数量的字节代码指令;
b. 线程主动让出控制权(可以调用 time.sleep(0) 来完成)。
把线程设置回睡眠状态(切换出线程);
解锁 GIL;
重复上述步骤
-
退出线程
当一个线程完成函数的执行时,它就会退出。
-
退出的方法还有:
通过调用如 thread.exit() 之类的退出函数;
如 sys.exit() 之类的退出 Python 进程的标准方法;
抛出 SystemExit 异常,来使线程退出。
不能直接“终止”一个线程;
在 Python 中使用线程
Python 虽然支持多线程编程,但是还需要取决于它所运行的操作系统。
支持多线程的操作系统:绝大多数类 UNIX 平台(如 Linux、Solaris、Mac OS X、*BSD等)以及 Windows 平台;
-
要确定解释器(或者说你的系统)是否支持线程,可以从交互式解释器中尝试导入 thread 模块,如果可用则不会产生错误。如下:
>>> import thread
-
如果 Python 解释器没有将线程支持编译进去,模块导入将会失败
-
>>> import thread
Traceback (most recent call last): File "<stdin>", line 1, in <module>ModuleNotFoundError: No module named 'thread'
-
**注:在 Python 3 中 thread 模块被重命名为 _thread (原因为平常使用不推荐用 thread 模块,只建议那些想访问线程的更底层级别的专家使用)。
不使用线程的情况
通过一个简单的例子代码来演示在不使用线程的情况下是如何工作的,方便后面对比使用线程的情况。以下为代码:
#!/usr/bin/env python
from time import sleep, ctime
def loop0():
print('start loop 0 at:', ctime())
sleep(4)
print('loop 0 done at:', ctime())
def loop1():
print('start loop 1 at:', ctime())
sleep(3)
print('loop 1 done at:', ctime())
def main():
print('starting at:', ctime())
loop0()
loop1()
print('all DONE at:', ctime())
if __name__ == '__main__':
main()
运行后的输出结果:
starting at: Sun Jul 22 17:15:13 2018
start loop 0 at: Sun Jul 22 17:15:13 2018
loop 0 done at: Sun Jul 22 17:15:17 2018
start loop 1 at: Sun Jul 22 17:15:17 2018
loop 1 done at: Sun Jul 22 17:15:20 2018
all DONE at: Sun Jul 22 17:15:20 2018
Python 的线程模块
Python 提供了多个模块来支持多线程编程,包括 thread 、threading 和 Queue 模块等。
thread 模块提供了基本的线程和锁定支持;
threading 模块提供了更高级别、功能更全面的线程管理;
Queue 模块可以创建一个队列数据结构,用于在多线程之间进行共享;
-
在实际进行多线程编程过程中应该避免使用 thread 模块:
threading 模块更加先进、有更好的进程支持,thread 模块中的一些熟悉会和 threading 模块冲突;
-
thread 模块拥有的同步原语注释只有一个(同步原语用于控制执行和访问);
[注释] 常见的比如锁(Lock)、可重入锁(RLock) thread 模块对进程何时退出没有控制。当主线程结束时,所有其它线程也都强制结束,不会发出警告或者进行适当的清理。