Python 多线程使用场景
1 前言
当初在学习 Python
多线程的时候就了解到: 由于 GIL
的原因, Python
解释器只允许同一时间执行一个线程。
随着相关基础知识的学习,渐渐明白了这意味着什么,自然而然的,也就思考起了 Python
多线程的应用场景。
2 GIL
全局解释器锁(英语:Global Interpreter Lock,缩写GIL),是计算机程序设计语言解释器用于同步线程的一种机制,它使得任何时刻仅有一个线程在执行。
使用多线程的一个目的就是希望通过多个线程的 并发 执行提高程序的执行效率,但是因为 GIL
的原因,使得多线程的 并发性 荡然无存.
全局只允许同一时间执行一个线程意味着: 如果是多线程程序,为了保证各个线程都能完成自身的任务,势必需要进行频繁的 线程切换 操作。
3 线程切换
线程切换 会带来不小的开销,频繁的线程切换会造成资源的浪费。但是在其他环境中,线程可以 并发 的执行,并发带来的效率的提高完全可以忽视因为线程切换带来的消耗。
但是在 Python
中,因为 GIL
的存在,多线程带来的 并发性 不在存在,但线程切换的消耗却没有一点减少。
这似乎意味着,多线程不仅没有带来性能的提升,而且还因为线程切换的原因,使得程序的性能降低了。
多线程编程往往还会提高编码难度,这样一来, Python
中的多线程似乎就失去了存在的价值。
但是,存在即是道理,虽然 Python
多线程存在各种各样的问题,但还是要考虑一种情况引起的线程切换。
4 I/O 操作
曾经,我以为 I/O
操作也是由 CPU
完成的,程序执行 I/O
操作的时候就是 CPU
不断执行神奇的指令从磁盘读写数据。
然后,在学习操作系统的过程中,才发现, I/O
操作是由 磁盘 完成的。
需要执行 I/O
操作的时候, CPU
向 磁盘 发起通知,然后就可以去执行其他东西了。
当 磁盘 完成相应的 I/O
操作后,向 CPU
发起通知, CPU
在回来继续执行后续的指令。
这也就意味着,当某一个线程等待 I/O
操作完成的时候,可以切换到其他线程完成其他工作。
5 使用场景
到了这里, Python
多线程的使用场景就很明了了。
常规情况下,线程切换是在执行一定数量的指令(3.2 以前)或执行一定时间后(3.2 以后)进行。
这对于 CPU 密集型 的程序来说是不利的,因为 CPU 密集型 的程序主要的消耗集中在执行 CPU
指令上,而 Python
中的多线程因为 GIL
的原因会带来 线程切换 的巨大开销,降低程序性能。
对于 I/O 密集型 的程序,由于 I/O 操作可以交付给 磁盘 完成,此时 GIL
带来的负面影响降到了最低。
因此, Python
多线程适合的使用场景为: I/O 密集型 的应用程序。
对于 CPU 密集型 的程序, 多进程 会带来比 多线程 更好的性能。
6 结语
Python
的多线程适合用在什么地方,晚上早就有很多的讨论了,结论也早已存在。
但是,得出这一结论的思考过程,却是印证所学基础知识的好机会。
多线程和单线程在执行 CPU 密集型 和 I/O 密集型 的比较可以看一看这篇文章: