Phase 8.2: Solver-Isolation ohne subprocess-Codestrings

Setzt den Isolationsteil von Paket 1 aus Verbesserungen_02.md um. Der Plan
nannte zwei Programme; beim Suchen kam ein drittes dazu, das dasselbe Muster
verwendete.

Ein_System_Vier_Ansaetze.py und Benchmark_Skalierung.py hielten ihre vier
Solvervarianten als Zeichenketten in einem Dictionary und gaben sie an
"python -c" weiter - bei Benchmark_Skalierung.py sogar mit
.format()-Platzhaltern fuer die Instanzgroesse. Aus jeder Variante ist jetzt
eine gewoehnliche Funktion mit lokalem Import geworden.
Solverwechsel_CPSAT_HiGHS.py rief sich selbst ueber sys.argv erneut auf;
auch das entfaellt.

Ausgefuehrt wird ueber einen ProcessPoolExecutor mit zwei Einstellungen, die
beide noetig sind: mp_context "spawn" (frischer Interpreter statt geerbtem
Speicher - unter Linux ist fork der Standard) und max_tasks_per_child=1 (ein
neuer Prozess je Aufgabe; ohne das verwendet der Pool seinen Arbeiter
wieder, und beim zweiten Solver ist der Konflikt zurueck). Nachgemessen:
vier Aufgaben, vier verschiedene PIDs.

Der zweite Punkt hat einen eigenen Warnkasten bekommen, weil der Fehler
leicht zu machen und schwer zu finden ist: Der Absturz kaeme nicht beim
ersten Solver, sondern beim zweiten - und saehe aus wie ein Problem des
zweiten.

Regel 4, dreifach geprueft. Ein_System_Vier_Ansaetze.py: identisch bis auf
die Zeitspalte, einschliesslich der Spannweite 2,41e-08, auf die sich der
Merksatz des Kapitels beruft. Benchmark_Skalierung.py: alle zwoelf
Zielwerte und alle drei Spannweiten bitgleich; Zeiten und Speicher haben
sich verschoben, beide sind im Abdruck seit jeher als hardwareabhaengig
gekennzeichnet. Solverwechsel_CPSAT_HiGHS.py: Ausgabe ohne Zeiten
unveraendert.

Bewusst subprocess bleibt Mutationstest.py: Dort wird pytest auf einer
mutierten Kopie in einem temporaeren Verzeichnis gestartet - ein externes
Werkzeug auf veraenderten Dateien, nicht die Isolation eines Imports.

Neu im Kapitel Oekosystem: ein Abschnitt "Wie die Isolation aussieht, wenn
sie tragen soll" - warum ein Codestring die schlechteste Umsetzung von
"eigener Prozess" ist. Anhang C nennt jetzt ebenfalls ProcessPoolExecutor.

Ein eigener Fehler, gefunden und abgesichert: Ich hatte dem neuen ### ein
{#sec:...}-Label gegeben. ABSCHNITT_RE erkennt nur "## " - das Label waere
nie registriert worden und jeder Verweis darauf ins Leere gelaufen, ohne
Warnung. Label entfernt, --check meldet den Fall jetzt. Gegengetestet.

Stand: 818 Querverweise, 76 Programme, 33 pytest-Tests, PDF 760 Seiten, 69
netzfreie Programme fehlerfrei.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
dschlueter 2026-09-08 12:39:34 +02:00
commit 862e92bc7b
29 changed files with 2401 additions and 1912 deletions

View file

@ -77,14 +77,14 @@ sie unerwartet ab, ist etwas kaputtgegangen.
| Kapiteldateien | 22 | **36** (31 + 5 Teil-Synthesen) |
| Kapitel | 15 | **23** |
| Anhänge | 4 | **5** |
| Zeilen im Gesamtdokument | 11 082 | **28 510** |
| Größe des Gesamtdokuments | 606 KB | **1 618 KB** |
| Hauptüberschriften | 131 | **303** |
| Zeilen im Gesamtdokument | 11 082 | **28 565** |
| Größe des Gesamtdokuments | 606 KB | **1 622 KB** |
| Hauptüberschriften | 131 | **302** |
| registrierte Abschnitte | 122 | **296** |
| aufgelöste Querverweise | 314 | **815** (0 unaufgelöst) |
| aufgelöste Querverweise | 314 | **818** (0 unaufgelöst) |
| Indexmarken | 295 | **328** |
| Beispielprogramme | 41 | **76** (alle lauffähig) |
| PDF-Seiten | — | **758** |
| PDF-Seiten | — | **760** |
| Notebooks | — | **25** |
| Plotly-Figuren | — | **4** |
| Diagramme (SVG) | 26 | **33**, davon **19** mit Generatorskript (16 Skripte) |
@ -1770,6 +1770,58 @@ Gegengetestet mit beiden Bruchformen.
Stand danach: **36 Dateien** (31 + 5 Synthesen), 296 Abschnitte, **815** Querverweise,
303 Hauptüberschriften, PDF **758** Seiten.
### ✅ 8.2 Solver-Isolation ohne `subprocess`-Codestrings
Setzt den Isolationsteil von Paket 1 aus `Verbesserungen_02.md` um. Der Plan nannte zwei
Programme; beim Suchen kam ein **drittes** dazu, das dasselbe Muster verwendete.
**Was ersetzt wurde.** `Ein_System_Vier_Ansaetze.py` und `Benchmark_Skalierung.py` hielten
ihre vier Solvervarianten als **Zeichenketten** in einem Dictionary und gaben sie an
`python -c` weiter — bei `Benchmark_Skalierung.py` sogar mit `.format()`-Platzhaltern für
die Instanzgröße. Aus jeder Variante ist jetzt eine gewöhnliche Funktion mit **lokalem
Import** geworden. `Solverwechsel_CPSAT_HiGHS.py` rief sich selbst über `sys.argv` erneut
auf; auch das entfällt.
Ausgeführt wird über einen `ProcessPoolExecutor` mit zwei Einstellungen, die zusammen die
Garantie ergeben — und beide sind nötig:
* `mp_context="spawn"` — frischer Interpreter statt geerbtem Speicher. Unter Linux ist
`fork` der Standard, und damit wäre alles bereits Importierte auch im Kind importiert.
* `max_tasks_per_child=1` — ein **neuer** Prozess je Aufgabe. Ohne das verwendet der Pool
seinen Arbeiter wieder, und beim zweiten Solver ist der Konflikt zurück. Nachgemessen:
vier Aufgaben, vier verschiedene PIDs.
Der zweite Punkt hat einen eigenen ⚠️-Kasten bekommen, weil der Fehler leicht zu machen und
schwer zu finden ist: Der Absturz käme nicht beim ersten Solver, sondern beim zweiten — und
sähe aus wie ein Problem des zweiten.
**Regel 4, dreifach geprüft.** Alle drei Programme drucken Ausgaben, die im Buch stehen:
* `Ein_System_Vier_Ansaetze.py`: identisch bis auf die Zeitspalte, **einschließlich der
Spannweite 2,41 · 10⁻⁸**, auf die sich der Merksatz des Kapitels beruft.
* `Benchmark_Skalierung.py`: **alle zwölf Zielwerte und alle drei Spannweiten
bitgleich**; Zeiten und Speicher haben sich verschoben, beide sind im Abdruck seit jeher
als hardwareabhängig gekennzeichnet.
* `Solverwechsel_CPSAT_HiGHS.py`: Ausgabe ohne Zeiten unverändert.
**Was bewusst `subprocess` bleibt:** `Mutationstest.py`. Dort wird pytest auf einer
**mutierten Kopie** in einem temporären Verzeichnis gestartet — ein externes Werkzeug auf
veränderten Dateien, nicht die Isolation eines Imports. Für diesen Fall ist `subprocess`
richtig.
**Neu im Kapitel Ökosystem:** ein Abschnitt „Wie die Isolation aussieht, wenn sie tragen
soll" — warum ein Codestring die schlechteste Umsetzung von „eigener Prozess" ist (unsichtbar
für Editor, Linter und Testwerkzeug; Tippfehler fallen erst zur Laufzeit auf; übergeben
lassen sich nur Zeichenketten). Anhang C nennt jetzt ebenfalls `ProcessPoolExecutor` statt
`subprocess`.
**Ein eigener Fehler, gefunden und abgesichert:** Ich hatte dem neuen `###` ein
`{#sec:...}`-Label gegeben. `ABSCHNITT_RE` erkennt nur `## ` — das Label wäre nie
registriert worden, und jeder Verweis darauf ins Leere gelaufen, ohne Warnung. Label
entfernt, und `--check` meldet diesen Fall jetzt. Gegengetestet.
Stand danach: 818 Querverweise, PDF **760** Seiten, 69 netzfreie Programme fehlerfrei.
---
## 8. Commit-Historie des V04-Strangs