python / python/cpython

asyncio.subprocess spawning can block

Offen
#146,181 4 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

stdlib topic-asyncio type-bug
Vorherrschende Sprache
Python
Sterne
77.2k
Forks
35.9k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

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

Linked PRs
  • gh-154111

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Verfolge den Aufrufpfad von _make_subprocess_transport() in Lib/asyncio/unix_events.py über Lib/asyncio/base_subprocess.py und subprocess.Popen() in Lib/subprocess.py. Prüfe die verlinkte Arbeit zu gh-154111, bevor du fortfährst; die Fertigstellung sollte verhindern, dass der Start von subprocess die Ereignisschleife blockiert, und eine Regressionstestabdeckung für das gemeldete Verhalten enthalten.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
python
Bereich
operating-systems
Issue-Typ
Bug
Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Aktivitätsstatus
Veraltet
Klarheit
Muss geklärt werden
Anfängerfreundlichkeit
30/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.