You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python异步进程与Semaphore出现死锁:原因是什么?

为何这段代码会出现死锁?

以下是出现死锁的代码:

#!/usr/bin/env python3

import asyncio

async def _stream_subprocess(id: int, command: "list[str]"):
    proc = await asyncio.create_subprocess_exec(*command, stdout=asyncio.subprocess.PIPE)
    await proc.wait()
    print(f"{id}: Done")


async def run(id: int, command: "list[str]"):
    print(f"{id}: Running")
    await _stream_subprocess(id, command)
    print(f"{id}: Throwing")

    raise RuntimeError("failed")


async def run_with_parallelism_limit(id: int, command: "list[str]", limit: asyncio.Semaphore):
    async with limit:
        print(f"{id}: Calling run")
        await run(id, command)
        print(f"{id}: Run finished")


async def main():
    sem = asyncio.Semaphore(1)
    await asyncio.gather(
        run_with_parallelism_limit(0, ["python", "--version"], sem),
        run_with_parallelism_limit(1, ["python", "--version"], sem),
    )


if __name__ == "__main__":
    asyncio.run(main())

程序的输出结果:

0: Calling run
0: Running
0: Done
0: Throwing
1: Calling run
1: Running

死锁原因

问题核心在_stream_subprocess函数的实现:

  • 创建子进程时指定了stdout=asyncio.subprocess.PIPE,但完全没有读取管道中的输出内容。
  • 子进程尝试向stdout管道写入数据时,一旦管道缓冲区被填满,子进程会被阻塞,无法正常退出。
  • await proc.wait()会一直等待子进程终止,而子进程因管道阻塞无法完成退出流程,导致当前任务永久挂起,最终整个程序陷入死锁。

即使python --version输出量极小,asyncio的子进程机制中,未读取的管道也会破坏子进程的正常退出逻辑,进而触发死锁。

解决方法

有两种简单的修复思路:

方法1:读取管道内容

在等待子进程结束前,主动读取stdout管道的所有内容,避免子进程阻塞:

async def _stream_subprocess(id: int, command: "list[str]"):
    proc = await asyncio.create_subprocess_exec(*command, stdout=asyncio.subprocess.PIPE)
    # 读取stdout内容,释放管道缓冲区
    await proc.stdout.read()
    await proc.wait()
    print(f"{id}: Done")

方法2:不捕获stdout

如果不需要获取子进程的输出,直接移除stdout参数,让子进程输出直接流向父进程的stdout:

async def _stream_subprocess(id: int, command: "list[str]"):
    proc = await asyncio.create_subprocess_exec(*command)
    await proc.wait()
    print(f"{id}: Done")

内容的提问来源于stack exchange,提问作者Timmmm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 14:07:03