Python 线程与套接字

5 投票
3 回答
3219 浏览
提问于 2025-04-16 11:22

我有一个“我只是想理解”的问题……

首先,我在Ubuntu上使用的是Python 2.6.5。

那么……在Python中,线程(通过线程模块)其实只是“线程”,它只是告诉全局解释器锁(GIL)在一定时间内运行每个“线程”的代码块等等……这里实际上并没有真正的线程。

所以问题来了——如果我在一个线程中有一个阻塞的套接字,现在我发送数据并让这个线程阻塞大约5秒。我本以为这会阻塞整个程序,因为这是一个C语言命令(sock.send),它让线程阻塞。但我很惊讶地发现主线程继续运行。

所以问题是——当遇到像发送这样的阻塞命令时,GIL是如何继续运行其余代码的?难道这里不需要使用真正的线程吗?

谢谢。

3 个回答

5

GIL(全局解释器锁)其实就是一个锁,它本身并不执行任何操作。相反,Python解释器会根据需要来获取和释放这个锁。一般来说,当运行Python代码时,这个锁是被保持住的,但在调用一些底层函数(比如sock.send)时,这个锁会被释放。因为Python线程是真正的操作系统级别的线程,所以多个线程不会同时运行Python代码。不过,如果有一个线程在调用一个耗时的C语言函数时,GIL会被释放,这样另一个Python代码的线程就可以运行,直到第一个线程完成。

6

Python的GIL维基页面提到:

需要注意的是,一些可能会阻塞或者运行时间较长的操作,比如输入输出、图像处理和NumPy的数值计算,这些操作是在GIL之外进行的。

12

Python使用的是“真实”的线程,也就是底层平台提供的线程。在Linux系统上,它会使用pthread库(如果你感兴趣,可以查看这个实现)。

Python线程的一个特别之处在于有个叫GIL的东西:一个线程只有在持有这个全局锁的情况下,才能修改Python的数据结构。因此,很多Python操作无法充分利用多个处理器核心。不过,如果一个线程在等待网络连接(也就是有个阻塞的socket),它就不会持有GIL,这样就不会影响其他线程。

很多人对GIL的理解有误,以为在Python中线程几乎没什么用。其实,GIL只阻止了“纯”Python代码在多个处理器核心上同时执行。如果你用线程来让图形界面更流畅,或者在等待输入输出时运行其他代码,GIL就不会对你造成影响。如果你用线程在一些C扩展(比如NumPy/SciPy)中并行运行代码,GIL也不会影响你。

撰写回答