Skip to content

asyncio.subprocess spawning can block #146181

@charles-dyfis-net

Description

@charles-dyfis-net

Bug report

Bug description:

asyncio.create_subprocess_exec() and asyncio.create_subprocess_shell() call subprocess.Popen() synchronously on the event loop thread. Popen._execute_child() performs a blocking os.read() on a CLOEXEC error pipe (Lib/subprocess.py, current main line 1995) that doesn't return until the child completes execve(). This blocks the event loop for the duration of:

  1. fork() / posix_spawn() — page-table duplication proportional to parent process size
  2. Child-side setup (signal disposition, fd operations, chdir, uid/gid changes)
  3. execve() — kernel loads the binary, maps pages before applying O_CLOEXEC

The call chain on the event loop thread is:

_make_subprocess_transport()  [async — Lib/asyncio/unix_events.py:197]
  → _UnixSubprocessTransport.__init__()  [sync]
    → BaseSubprocessTransport.__init__()  [sync — Lib/asyncio/base_subprocess.py:40]
      → self._start()  [sync]
        → subprocess.Popen()  [sync]
          → _execute_child()  [sync — Lib/subprocess.py:1878]
            → os.read(errpipe_read, 50000)  [BLOCKS — line 1995]

In production, we have observed this blocking the event loop for multiple seconds when a Python process spawns a large binary (with a substantial statically-linked dependency set) on a system that was within operational parameters for memory usage (no ongoing swapping or similar) but subject to IO read contention slowing the binary-loading process.

The original python/asyncio#414 identified this in 2016; the asyncio repo was archived without resolution or migration to cpython's tracker.

#81444 would serve to fix this issue (by having asyncio.subprocess dispatch to a thread). However, I'm not sure it constitutes the only fix, or even an ideal fix — we should be able to watch for the FIFO either closing or having data available to read using natively asynchronous syscalls.


Observed in production on Python 3.13; determination that the issue still exists in 3.14 and current main based on source tree inspection.

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions