Zum Inhalt springen

Aufgabe 07 - Parallel oder nacheinander?

Zu Zen-Modus wechseln

Aus der Pizzeria wird ein Betrieb: mehrere Bestellungen gleichzeitig. Sie messen den Unterschied zwischen sequentieller und paralleler Ausführung, werten Sammelaktionen mit Einzelbericht aus, bauen Timeouts und stoßen an die Grenze des Event Loops, hinter der Worker beginnen (siehe Kapitel Nebenläufigkeit II).

  • Kapitel Nebenläufigkeit II vollständig; Ihre Pizzeria aus Aufgabe 05 (gehärtet in Aufgabe 06).
  • Sie koordinieren parallele Abläufe mit Promise.all, allSettled und race.
  • Sie belegen Parallelisierungs-Entscheidungen mit Messwerten.
  • Sie grenzen asynchrones Warten von echter Parallelität (Worker) ab.
  • Reproduktion: die Kombinatoren nach Vorlage einsetzen (Teil A).
  • Reorganisation und Transfer: Zeitverhalten messen, Timeouts konstruieren, Ergebnisse interpretieren (Teile B und C).
  • Reflexion, Problemlösung und Urteilsbildung: die Grenze des Modells nachweisen und die Worker-Lösung bewerten (Teil D).

Die Übung ist auf etwa zwei Stunden ausgelegt. Teil D ist der Expertenteil.

  1. Fünf Bestellungen nacheinander (Schleife mit await): Gesamtdauer mit performance.now() messen und notieren.
  2. Fünf Bestellungen parallel (Promise.all über orders.map(...)): Gesamtdauer messen. Erklären Sie das Verhältnis der beiden Zeiten in zwei Sätzen (Stichwort: das langsamste Promise).
  3. Provozieren Sie eine verbrannte Pizza und beobachten Sie: Promise.all reißt alle Bestellungen mit in den Fehlerfall, auch die gelungenen.
  1. Ersetzen Sie Promise.all durch Promise.allSettled und erzeugen Sie einen Bericht: 4 delivered, 1 burned, mit Auflistung der Fehlgeschlagenen samt Grund.
  2. Begründen Sie in zwei Sätzen fachlich, warum hier allSettled das richtige Werkzeug ist und wann dagegen all korrekt wäre (das Kapitel nennt das Kriterium).
  1. Implementieren Sie withTimeout<T>(promise: Promise<T>, milliseconds: number): Promise<T> mit Promise.race: Dauert der Vorgang länger, scheitert er mit "too slow, order canceled".
  2. Testen Sie mit einem Timeout knapp über und knapp unter der typischen Bestelldauer; beide Fälle im Log nachweisbar.
  3. Erklären Sie in zwei Sätzen den Schönheitsfehler von race (was macht der Verlierer?) und wie AbortController sich davon unterscheidet.
  1. Bauen Sie eine bewusst teure synchrone Funktion (etwa eine naive rekursive Fibonacci-Berechnung mit n um 40) und starten Sie parallel dazu eine “Uhr” (setInterval, jede Sekunde ein Log). Beobachtung: Die Uhr stottert oder steht, solange gerechnet wird. Erklären Sie warum, mit dem Event-Loop-Modell.
  2. Lagern Sie die Berechnung in einen Worker aus (Node: worker_threads, Browser: Web Worker) und weisen Sie nach, dass die Uhr jetzt durchläuft, während gerechnet wird.
  3. Beschreiben Sie in drei Sätzen den Unterschied zwischen “asynchron” (Warten überbrücken) und “echt parallel” (gleichzeitig rechnen) und ordnen Sie zu, wofür der Event Loop genügt und wofür nicht.
  4. Zusatz: Begrenzen Sie die Gleichzeitigkeit des Ansturms aus Teil A auf höchstens zwei Bestellungen zugleich (eine einfache Warteschlangen-Logik genügt) und messen Sie erneut. In welcher realen Situation ist genau diese Begrenzung nötig?
  1. Wovon hängt die Gesamtdauer von Promise.all ab?
  2. Nach welchem fachlichen Kriterium wählt man zwischen all und allSettled?
  3. Was liefert allSettled pro Eintrag, und wie unterscheidet man Erfolg von Fehlschlag?
  4. Warum stottert die Uhr bei schwerer synchroner Rechenarbeit, obwohl setInterval “asynchron” ist?
  5. Worüber kommunizieren Worker mit dem Hauptthread, und was teilen sie nicht?

kitchen.ts (plus Worker-Datei), die Messwerte aus den Teilen A und D als Tabelle und die schriftlichen Erklärungen als Kommentar.