Python 线程真的并发了吗?从 GIL 执行窗口说起

来源:站长平台作者:永濑头衔:网络博主
导读:本期聚焦于小伙伴创作的《Python 线程真的并发了吗?从 GIL 执行窗口说起》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Python 线程真的并发了吗?从 GIL 执行窗口说起》有用,将其分享出去将是对创作者最好的鼓励。

Python作为一门广泛使用的编程语言,其多线程机制一直是开发者讨论的热点,核心争议点就在于全局解释器锁GIL是否会完全阻塞线程的并发执行。要回答Python线程是否真的并发,首先需要理解GIL的设计初衷和执行窗口的工作逻辑。

Python 线程真的并发了吗?从 GIL 执行窗口说起

GIL是什么

GIL全称是Global Interpreter Lock,即全局解释器锁,是CPython解释器引入的一种互斥锁机制。它的核心作用是保证同一时刻只有一个线程能够执行Python字节码,避免多个线程同时操作Python对象时出现内存管理混乱的问题,因为CPython的内存管理不是线程安全的。

GIL的执行窗口机制

GIL并不是让线程一直持有锁直到执行结束,而是采用执行窗口的方式切换锁的持有权。在Python3.2及之后的版本中,线程默认会在一个时间窗口内持有GIL,窗口大小通常是5毫秒,窗口结束后会主动释放GIL,其他线程可以竞争获取锁继续执行。

我们可以通过一段简单的代码观察线程的执行切换:

import threading
import time

def task():
    # 线程执行的任务,打印当前线程名和执行时间
    for i in range(3):
        print(f"线程 {threading.current_thread().name} 执行第 {i} 次,时间:{time.time()}")
        time.sleep(0.1)

if __name__ == "__main__":
    t1 = threading.Thread(target=task, name="线程1")
    t2 = threading.Thread(target=task, name="线程2")
    t1.start()
    t2.start()
    t1.join()
    t2.join()

运行这段代码可以看到两个线程会交替打印执行信息,说明线程并不是完全串行执行的,而是会在GIL的调度下切换执行。

不同场景下的线程并发表现

IO密集型任务

IO密集型任务指的是线程大部分时间在等待IO操作完成,比如网络请求、文件读写、数据库查询等。这类任务中,线程在等待IO时会主动释放GIL,其他线程可以获取GIL执行,因此Python线程在IO密集型场景下是可以实现有效并发的,能够提升程序的整体执行效率。

下面是一个IO密集型任务的示例,模拟文件读取的等待过程:

import threading
import time

def io_task():
    # 模拟IO等待,比如读取文件或者网络请求
    print(f"{threading.current_thread().name} 开始IO等待")
    time.sleep(1)  # 模拟1秒的IO耗时
    print(f"{threading.current_thread().name} IO等待结束")

if __name__ == "__main__":
    start = time.time()
    # 创建两个线程执行IO任务
    t1 = threading.Thread(target=io_task, name="IO线程1")
    t2 = threading.Thread(target=io_task, name="IO线程2")
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    end = time.time()
    print(f"总耗时:{end - start:.2f}秒")

运行后可以看到总耗时接近1秒,而不是2秒,说明两个线程在IO等待时并发执行了。

CPU密集型任务

CPU密集型任务指的是线程大部分时间在进行计算操作,比如循环运算、数据处理、加密解密等。这类任务中,线程会一直占用CPU执行字节码,直到GIL的执行窗口结束才会释放锁,而执行窗口的时间很短,线程切换会带来额外的开销,因此Python线程在CPU密集型场景下无法实现真正的并行,甚至因为切换开销导致效率比单线程更低。

下面是CPU密集型任务的示例,模拟大量计算:

import threading
import time

def cpu_task():
    # 模拟CPU密集型计算,累加1到1000000
    total = 0
    for i in range(1000000):
        total += i
    print(f"{threading.current_thread().name} 计算完成,结果:{total}")

if __name__ == "__main__":
    start = time.time()
    # 单线程执行
    cpu_task()
    cpu_task()
    single_thread_time = time.time() - start
    print(f"单线程总耗时:{single_thread_time:.2f}秒")

    # 多线程执行
    start = time.time()
    t1 = threading.Thread(target=cpu_task, name="CPU线程1")
    t2 = threading.Thread(target=cpu_task, name="CPU线程2")
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    multi_thread_time = time.time() - start
    print(f"多线程总耗时:{multi_thread_time:.2f}秒")

运行后可以看到多线程的总耗时通常比单线程更长,说明CPU密集型任务下Python线程没有实现有效并发。

总结

Python线程是否真的并发不能一概而论,需要结合任务类型判断。在IO密集型任务中,线程会在等待IO时释放GIL,其他线程可以执行,因此能够实现并发,提升效率;在CPU密集型任务中,线程会一直占用GIL直到执行窗口结束,无法利用多核CPU实现并行,甚至会因为线程切换开销降低效率。如果需要在CPU密集型场景下提升性能,可以选择多进程方案,或者使用没有GIL的Python解释器比如Jython、IronPython,也可以将计算部分用C扩展实现来规避GIL的限制。

PythonGIL线程并发执行窗口修改时间:2026-07-15 17:15:36

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。