Baike.dev
Anmelden
> 返回资讯列表
news_article.exe
📰

Ich tötete den Prozess und der Abfluss hing immer noch: Ein Enkelkind hielt die Pfeife

I killed the process and the drain still hung: a grandchild held the pipe

2026年9月6日5 次浏览来源:Dev.to 阅读原文

Ein Programm von mir hing vierzig Minuten lang. Nicht mit tausend Schleifen pro Sekunde drehen: bei null Prozent CPU. Es machte nicht zu viel Arbeit; es machte überhaupt keine Arbeit. Und trotzdem würde es nicht enden. Das Programm macht etwas Gemeinsames: Es orchestriert externe Kommandozeilen-Tools. Es startet eine, liest, was es in die Standardausgabe schreibt, und geht zum nächsten über, wenn es fertig ist. Es bleibt also nicht hängen, wenn ein Werkzeug zieht, jedes hat eine Auszeit: Wenn es feuert, wird der Prozess getötet und wir machen weiter. Das ist der Teil, der gescheitert ist, und es ist gescheitert, wo niemand hinschaut: nachdem er den Prozess getötet hat. Das Töten des Prozesses schließt das Rohr nicht Wenn Sie die Ausgabe eines Teilprozesses lesen, lesen Sie aus einer Pipe: ein Ende schreibt (der Teilprozess), das andere liest (Sie). Ihr Leser endet nicht, wenn der Subprozess ...

Ein Programm von mir hing vierzig Minuten lang. Nicht mit tausend Schleifen pro Sekunde drehen: bei null Prozent CPU. Es machte nicht zu viel Arbeit; es machte überhaupt keine Arbeit. Und trotzdem würde es nicht enden. Das Programm macht etwas Gemeinsames: Es orchestriert externe Kommandozeilen-Tools. Es startet eine, liest, was es in die Standardausgabe schreibt, und geht zum nächsten über, wenn es fertig ist. Es bleibt also nicht hängen, wenn ein Werkzeug zieht, jedes hat eine Auszeit: Wenn es feuert, wird der Prozess getötet und wir machen weiter. Das ist der Teil, der gescheitert ist, und es ist gescheitert, wo niemand hinschaut: nachdem er den Prozess getötet hat. Das Töten des Prozesses schließt das Rohr nicht Wenn Sie die Ausgabe eines Teilprozesses lesen, lesen Sie aus einer Pipe: ein Ende schreibt (der Teilprozess), das andere liest (Sie). Ihr Leser endet nicht, wenn der Subprozess stirbt. Es endet, wenn EOF ankommt, und die EOF eines Pipes kommt nur an, wenn das letzte Schreibende geschlossen ist. Fast immer stimmen sie überein: Der Subprozess ist der einzige Autor, er stirbt, sein Ende schließt, EOF kommt an, Ihr Leser beendet. Alles in Mikrosekunden. Aber "fast immer" ist nicht "immer". Das Tool, das ich startete, startete wiederum ein anderes - ein Enkelkind. Und dieses Enkelkind erbte das Schreibende der Pfeife, denn auf Unix erbt ein Kind die offenen Deskriptoren seiner Eltern, wenn nicht anders gesagt. Als das Timeout feuerte, tötete ich das Kind. Sein Ende ist geschlossen. Aber das Enkelkind war noch am Leben, mit seiner Kopie des Deskriptors offen. Das letzte Schreibende war nicht geschlossen. EOF kam nie. Und mein Leser saß und wartete auf einen EOF, der niemals ankommen würde - bei null Prozent CPU, blockiert in einem, nicht zu unterscheiden von langsamer Arbeit -. Das Symptom, das täuscht Was dieses Versagen so schwer zu erkennen macht, ist, dass es nicht wie ein Versagen aussieht. Ein Infinite-Loop-Hang brennt CPU: Sie sehen es sofort. Dieser gibt nichts aus. Der Thread schläft im Kernel und wartet auf Daten, die nicht kommen. In der Prozessliste sieht es gesund aus. In den Metriken sieht es so aus, als würde es "eine Weile dauern". Die einzige Möglichkeit, "für immer hängen" von "langsam laufen" zu unterscheiden, besteht darin, den Fadenstapel zu betrachten und das zu sehen, was sich nie bewegt. Der Fix tötet nicht besser Der Reflex besteht darin, auch die Enkelkinder zu töten - eine Prozessgruppe, eine Sitzung, den ganzen Baum -. Manchmal kannst du, manchmal kannst du nicht: Ein Prozess kann der Gruppe entkommen, ein Enkelkind kann seine Eltern absichtlich überleben. Aber es gibt einen einfacheren und ehrlicheren Ausweg, und er kommt von einer einzigen Frage: Welcher Prozess genau wird diesen Deskriptor schließen? Wenn die Antwort lautet "keine, die ich kontrolliere", dann wartet auf EOF auf etwas, das nicht passieren wird. Und ein Warten auf etwas, das nicht passieren wird, wird nicht durch besseres Warten behoben: Es ist begrenzt. Die Lösung bestand darin, dem Abfluss selbst eine Auszeit zu geben. Nach dem Töten des Prozesses warten wir ein paar Sekunden auf EOF; Wenn es nicht kommt, verlassen wir das Lesen und gehen weiter. Was auch immer das Tool zuvor geschrieben hat, ist bereits erfasst, so dass nichts verloren geht. Und ein Deskriptor, den ein Enkelkind offen hält, spielt keine Rolle mehr: Niemand wartet auf unbestimmte Zeit darauf. Jedes Warten - eine Schleife, die sich dreht, bis eine Bedingung besteht, ein Deskriptor - hat eine Frage dahinter: Welcher Prozess wird diese Bedingung wahr machen? Wenn es keine gibt, ist das Warten unmöglich, und ein unmögliches Warten gibt keinen Fehler: Es sieht genau wie eine Arbeit aus, die eine Weile dauert. Null Prozent CPU, nicht voranschreiten, für immer. Bevor Sie das Warten schreiben, benennen Sie den Prozess, der es beenden wird. Wenn Sie es nicht benennen können, schreiben Sie es nicht ohne Cap.

> 分享:
Baike.dev

baike.dev hilft dir, starke Sprachen, Frameworks, Datenbanken, DevOps- und Cloud-Native-Tools zu entdecken.

Schnellzugriff

Über uns

Mitmachen

Kennst du ein starkes Entwickler-Tool? Teile es.

Tool einreichen
© 2026 baike.dev Entwickler-EnzyklopädieTäglich aktualisiert · Entdecke starke Entwickler-Tools