12 Punkte von darjeeling 2026-01-31 | Noch keine Kommentare. | Auf WhatsApp teilen

Zusammenfassung:

  • Das subprocess-Modul von Python und die Bibliothek psutil haben in den vergangenen 15 Jahren beim Warten auf das Ende eines Prozesses (wait()) die ineffiziente Methode des Busy-Loop-Pollings verwendet, bei der sleep und waitpid wiederholt aufgerufen werden.
  • Diese Methode verursacht unnötige CPU-Wake-ups, höheren Batterieverbrauch und Verzögerungen bei der Erkennung von Prozessenden (Latenz) und skaliert schlecht, wenn viele Prozesse überwacht werden.
  • Durch ein aktuelles Update wurde unter Linux echtes ereignisbasiertes Warten mit pidfd_open() und poll() implementiert, unter BSD/macOS mit kqueue().
  • Unter Windows gab es bereits mit WaitForSingleObject eine entsprechende Lösung, daher ändert sich dort nichts; auf POSIX-Systemen entfallen jedoch unnötige Kontextwechsel und die CPU-Auslastung nähert sich im Wartezustand 0 an.

Detaillierte Zusammenfassung:
1. Ein 15 Jahre lang bestehendes Problem: Busy-Loop-Polling
Seit in Python 3.3 der Parameter timeout zu subprocess.Popen.wait() hinzugefügt wurde, haben die Python-Standardbibliothek und die weit verbreitete Bibliothek psutil zum Warten auf das Ende eines Prozesses eine ineffiziente Methode verwendet.

Die bisherige Logik war einfach, aber ineffizient:

  1. Prozessstatus mit waitpid(WNOHANG) prüfen (nicht blockierend)
  2. Falls der Prozess noch nicht beendet ist, kurz sleep() ausführen (mit exponentiellem Backoff)
  3. Zu Schritt 1 zurückkehren und wiederholen
# Bisheriger Ansatz (Konzeptcode)  
import time, os  
  
def wait_busy(pid, timeout):  
    delay = 0.0001  
    while True:  
        # Prüfen, ob der Prozess beendet ist (Polling)  
        if os.waitpid(pid, os.WNOHANG) == (pid, status):  
            return status  
        time.sleep(delay)  
        delay = min(delay * 2, 0.040) # Wartezeit bis maximal 40 ms erhöhen  
  

Dieser Ansatz hat drei gravierende Nachteile.

  • CPU-Wake-ups: Selbst wenn die Wartezeit erhöht wird, muss das System periodisch aufwachen und den Status prüfen, was CPU-Zyklen verschwendet und Energie verbraucht.
  • Latenz: Zwischen dem tatsächlichen Ende eines Prozesses und dem Zeitpunkt, zu dem das Ende nach dem Aufwachen aus sleep erkannt wird, entsteht unvermeidlich eine Verzögerung.
  • Skalierbarkeit: In Serverumgebungen, in denen Hunderte oder Tausende Prozesse gleichzeitig überwacht werden, steigt dieser Overhead stark an.

2. Die Lösung: Ereignisbasiertes Warten für POSIX-Systeme
Alle POSIX-Systeme bieten Mechanismen (select, poll, epoll, kqueue), um Zustandsänderungen von File Descriptors zu erkennen. Python und psutil wurden kürzlich verbessert, um diese Mechanismen auch für die Erkennung von Prozess-PIDs zu nutzen.

  • Linux: Verwendet den Systemaufruf pidfd_open(), der 2019 mit dem Linux-5.3-Kernel eingeführt wurde. Er liefert einen File Descriptor zurück, der auf die Prozess-PID verweist und in poll() oder epoll() registriert werden kann, um auf ein Prozessende zu warten. (Seit Python 3.9 im Modul os enthalten)
  • BSD / macOS: Verwendet den Filter EVFILT_PROC des Systemaufrufs kqueue(), um Prozessereignisse effizient zu überwachen.
  • Windows: Unterstützte ereignisbasiertes Warten bereits über die API WaitForSingleObject, daher gibt es dort keine Änderungen.

3. Leistungsverbesserungen und Ergebnisse
Durch diese Änderung geht ein Prozess bei einem wait()-Aufruf aus Sicht des Kernels in einen Zustand des „interruptible sleep“ über. Das heißt: Er wartet ohne jeglichen CPU-Verbrauch ruhig im Kernelspace und wird sofort aufgeweckt, sobald ein Signal für das Prozessende eintritt.

Benchmarks mit /usr/bin/time -v und ähnlichen Tools zeigen, dass unnötige Kontextwechsel im Vergleich zum bisherigen Ansatz drastisch reduziert wurden und sich auch die Geschwindigkeit der Erkennung von Prozessenden unmittelbar verbessert hat. Das Update wurde sowohl in die Bibliothek psutil als auch in den CPython-Core übernommen, sodass Python-Entwickler künftig ohne eigene Codeänderungen von der Leistungssteigerung profitieren können.

Noch keine Kommentare.

Noch keine Kommentare.