Ubuntu环境下Python多线程无竞态条件,如何禁用GIL?
为什么Python多线程脚本未触发竞态条件,且GIL如何禁用?
我在Ubuntu 22.04 LTS机器上运行未加锁的Python脚本时,始终得到相同的输出,无法理解为什么没有发生线程切换从而引发竞态条件。
from threading import * lock = Lock() count = 0 def task(): global count for i in range(1000000): count += 1; if __name__ == '__main__': t1 = Thread(target=task) t2 = Thread(target=task) t1.start() t2.start() t1.join() t2.join() print(count)
上述代码始终输出一致的结果2000000。
执行命令dmidecode -t processor|grep Count -的输出为:
Core Count: 4 Thread Count: 8
执行命令cat /sys/devices/system/cpu/smt/control的输出为:
on
我通过终端执行该Python脚本:python3 file.py。
补充内容
def check_single_threaded(): active_threads = active_count() return active_threads == 1
该函数返回True。经进一步研究发现,这是由于Global Interpreter Lock(GIL)仅允许单个线程运行,请问有什么方法可以禁用它?
问题原因解析
- GIL调度逻辑:CPython的GIL会在执行一定数量的字节码(默认100条)或遇到I/O操作时释放,让其他线程有机会执行。但你的
count += 1操作虽然在字节码层面是三步(读值、加1、写回),但循环内的操作过于简单快速,线程可能在GIL触发切换前就完成了整个100万次循环,导致两个线程完全串行执行,自然不会出现竞态条件。 - active_count()的使用误区:你在主线程调用这个函数时,可能子线程还未启动或已经执行完毕,所以返回
1。如果把这个函数放到task()内部执行,就能看到正确的活跃线程数量。
禁用GIL的可行方案
CPython本身无法直接禁用GIL,但可以通过以下方式绕过GIL限制:
- 改用多进程:使用
multiprocessing模块,每个进程拥有独立的Python解释器和内存空间,完全不受GIL约束,适合CPU密集型任务。 - 使用无GIL的Python实现:比如PyPy(对CPU密集型任务优化好,部分场景自动规避GIL)、Jython(基于JVM实现,无GIL)、IronPython(基于.NET平台,无GIL)。
- 借助C扩展或第三方库:像
numpy、numba这类库的核心逻辑在C层面执行,执行时会自动释放GIL;也可以自行编写C扩展,在关键代码段手动释放GIL。 - 升级到Python 3.12+:新版本CPython对GIL做了大幅优化,多核场景下线程切换效率更高,但仍未完全移除GIL。
内容的提问来源于stack exchange,提问作者Kevin Martin
相关产品推荐
相关产品推荐

