Python中线程如何检测IO操作并自动释放GIL锁给其他线程执行?
Python中线程如何检测IO操作并自动释放GIL锁给其他线程执行?
底层 IO 接口手动释放 GIL,这个其实你看看 CPython 源代码就知道了。
Python的线程在遇到IO操作时,确实会自动释放GIL(全局解释器锁),让其他线程有机会执行。这个机制是由Python解释器内部实现的,具体来说:
-
IO操作检测:当线程执行标准库中的IO操作(如文件读写、网络请求等)时,这些操作会调用底层的C函数。这些C函数在进入阻塞状态前,会主动释放GIL。
-
GIL释放机制:在Python的C实现中,有一个宏
Py_BEGIN_ALLOW_THREADS,它会在IO操作前释放GIL;对应的Py_END_ALLOW_THREADS会在操作完成后重新获取GIL。例如,socket.recv()这样的函数在底层C代码中就会使用这些宏。 -
自动切换:GIL释放后,操作系统线程调度器会决定哪个线程(包括其他Python线程或非Python线程)获得CPU时间片。其他Python线程此时可以获取GIL并执行。
这里有个简单的代码示例展示IO操作时GIL的释放:
import threading
import time
import requests
def io_task(url):
print(f"线程 {threading.current_thread().name} 开始IO操作")
response = requests.get(url) # 这里会释放GIL
print(f"线程 {threading.current_thread().name} 完成,状态码: {response.status_code}")
# 创建两个线程同时进行网络请求
threads = []
for i in range(2):
t = threading.Thread(target=io_task, args=("https://httpbin.org/delay/1",))
threads.append(t)
t.start()
for t in threads:
t.join()
在这个例子中,两个线程几乎同时开始网络请求,因为第一个线程在requests.get()时释放了GIL,第二个线程就能立即执行。
需要注意的是,纯CPU密集型操作(比如大量数学计算)不会自动释放GIL,除非线程主动让出(比如调用time.sleep(0))。对于CPU密集型任务,建议使用多进程或异步编程。
总结:Python线程在IO操作时会通过底层C函数自动释放GIL。
最简单的, Python 标准库中所有的 io 操作都记录一下, 那么你基于标准实现的其他库你可以就知道了.
实在不行, 你还可以看看操作系统是不是有什么接口可以使用
do {
Py_BEGIN_ALLOW_THREADS
ret = fcntl(fd, code, buf);
Py_END_ALLOW_THREADS
} while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
能否解释下,感觉只看懂了线程开始和结束,循环 fcntl 是否结束
Py_BEGIN_ALLOW_THREADS 这个宏的意思就是释放 GIL,然后 Py_END_ALLOW_THREADS 再锁上
IO 的核心部分其实是系统内核完成的,调用内核的时候放开就行了
线程执行是抢占式的 是由系统来调度的

