Skip to main content
 首页 » 编程设计

python之python线程是如何工作的

2025年05月04日27开发

我想知道 python 线程是并发运行还是并行运行?

例如,如果我有两个任务并在两个线程中运行它们,它们是同时运行还是计划并发运行?

我知道 GIL 并且线程仅使用一个 CPU 内核。

请您参考如下方法:

这是一个需要大量解释的复杂问题。我将坚持使用 CPython,因为它是最广泛使用的并且我有经验。

  • Python 线程是一个系统线程,它需要 Python 解释器在运行时本地将其内容执行为字节码。 GIL 是特定于解释器(在本例中为 CPython)的锁,它强制每个线程获取解释器上的锁,防止两个线程同时运行,无论它们在哪个内核上。
  • 没有一个 CPU 内核可以同时运行多个线程。您甚至需要多个内核才能明智地谈论并行性。并发性与并行性不同——前者意味着两个线程之间的操作可以在任何一个完成之前交错,但两个线程不需要同时启动,而后者意味着可以同时启动的操作。如果这让您感到困惑,关于差异的更好描述是 here 。
  • 有多种方法可以在单核 CPU 中引入并发性——即让线程挂起(让自己进入休眠状态)并在需要时恢复——但是没有办法在单核中引入并行性。

  • 由于这些事实,因此,它取决于。
  • 系统线程本质上被设计为并发的 - 否则拥有操作系统就没有多大意义。它们是否以这种方式实际执行取决于任务:某处是否有原子锁? (正如我们将看到的,有!)
  • 执行 CPU 密集型计算的线程——其中有大量代码正在执行,同时解释器为每一行动态调用——获取 GIL 上的锁,以防止其他线程执行相同的操作。因此,在这种情况下,一次只有一个线程在所有内核上工作,因为没有其他线程可以获取解释器。

    话虽如此,线程在完成之前不需要保留 GIL,而是在需要时获取和释放锁。两个线程可能会交错其操作,因为 GIL 可以在代码块的末尾释放,被另一个线程抓取,在该代码块的末尾释放,等等。它们不会并行运行——但它们当然可以同时运行。
  • 另一方面,
  • I/O 绑定(bind)线程花费大量时间只是等待请求完成。这些线程不会获得 GIL - 当没有什么可以解释的时候,它们为什么会呢? - 所以当然你可以有多个 I/O 等待线程并行运行,每个线程一个核心。然而,需要将分钟代码编译为字节码(也许您需要处理您的请求?)再次上升到 GIL。
  • Python 中的进程在 GIL 中幸存下来,因为它们是与线程捆绑在一起的资源集合。每个进程都有自己的解释器,因此进程中的每个线程只需与自己的直接进程同级竞争 GIL。这就是为什么在 Python 中推荐使用基于进程的并行性的方法,即使它总体上消耗更多资源。

  • 结果

    因此,两个线程中的两个任务可以在 并行 中运行,前提是它们不需要访问 CPython 解释器。如果它们正在等待 I/O 请求或使用不需要 Python 解释器的合适的其他语言(例如 C)扩展,则可能会发生这种情况,使用外部函数接口(interface)。

    在交错原子操作的意义上,所有线程都可以并发运行。这些交错究竟有多原子 - 在代码块之后释放 GIL 吗?每行之后? - 取决于任务和线程。 Python 线程不必串行执行——一个线程完成,然后另一个线程开始——所以在这个意义上存在并发。