如果 GIL 存在,Python 中的多线程有啥意义?

Posted

技术标签:

【中文标题】如果 GIL 存在,Python 中的多线程有啥意义?【英文标题】:What's the point of multithreading in Python if the GIL exists?如果 GIL 存在,Python 中的多线程有什么意义? 【发布时间】:2019-03-01 15:12:53 【问题描述】:

据我了解,GIL 使线程无法单独利用一个核心。

这是一个基本问题,但是,threading 库的意义何在?如果线程代码的速度与普通程序相当,那似乎没用。

【问题讨论】:

它可用于解除对主线程的阻塞(例如 GUI 应用程序或类似应用程序)。如果你想使用多核,你应该尝试多处理(docs.python.org/3.7/library/multiprocessing.html 试试this question。简短的回答:它可能很有用,但可能不是你想象的那样。由于 GIL,一次只能有一个线程处理 Python,这意味着线程程序仍然可以串行运行。 multiprocessing 库对您似乎正在寻找的内容更有帮助,因为它实际上可以生成利用单个内核的进程。 感谢@questionable_code 和@Tom 的帮助。我正在研究多处理,我可能不得不使用它。我仍然很好奇为什么他们甚至拥有threading 库。似乎更适合代码组织。 看这个 (dabeaz.com/python/UnderstandingGIL.pdf) 和这个 (dabeaz.com/python/GIL.pdf) 谈话,很有趣。似乎多线程程序在 1 核上的运行速度比在 2 或 4 核上快得多。这些讨论已经很老了(2010 年),并且有人提到 Python 3.x 中的新 GIL,但我没有尝试过。 【参考方案1】:

在某些情况下,应用程序甚至可能无法完全利用一个内核,而使用线程(或进程)可能有助于做到这一点。

想想一个典型的网络应用程序。它接收来自客户端的请求,对数据库进行一些查询并将数据返回给客户端。鉴于大多数情况下 IO 操作比 CPU 操作慢一个数量级,因此此类应用程序正在等待 IO 完成。首先,它等待从套接字读取请求。然后它一直等到对数据库的请求被写入对数据库打开的套接字中。然后它等待来自数据库的响应,然后等待将响应写入客户端套接字。

等待 IO 完成可能需要 90%(或更多)的时间来处理请求。当单线程应用程序在等待 IO 时,它只是不使用内核并且内核可用于执行。因此,即使在单个内核上,此类应用程序也有空间供其他线程执行。

在这种情况下,当一个线程等待 IO 完成时,它会释放 GIL,另一个线程可以继续执行。

【讨论】:

【参考方案2】:

严格来说,CPython 支持 multi-io-bound-thread + single-cpu-bound-thread

io绑定方法:file.open、file.write、file.read、socket.send、socket.recv等python调用这些io函数时会释放GIL并获取GIL io函数返回后隐式

cpu bound方法:算术计算等

c 扩展方法:方法必须调用PyEval_SaveThread & PyEval_RestoreThread 明确告诉python解释器你在做什么

【讨论】:

以上是关于如果 GIL 存在,Python 中的多线程有啥意义?的主要内容,如果未能解决你的问题,请参考以下文章

python中的多线程

Python的多线程threading和多进程multiprocessing

pythonprocess多核更慢

GIL

python的多线程编程

为啥有人说Python的多线程是鸡肋?