====== LU07.L08 - Vorgegebene Massnahmen umsetzen ====== ===== Ergebnisse ===== Gemessen mit ''min(timeit.repeat(..., number=1, repeat=5))'' auf einem Notebook, Python 3.12. **Ihre absoluten Zahlen werden abweichen - die Grössenordnung der Faktoren nicht.** ^ Massnahme ^ vorher ^ nachher ^ Faktor ^ Begründung ^ | 1 list → set | 0.107 s | 0.000068 s | ~1500 | ''in'' auf einer Liste prüft im Schnitt die halbe Liste (O(n)), das Set berechnet einen Hash (O(1)) | | 2 Schleife → dict-Index | 0.0585 s | 0.00028 s | ~200 | Statt 2000 × 2000 Vergleichen (O(n²)) wird der Index einmal gebaut und dann direkt zugegriffen (O(n)) | | 3 Memoization | 0.0899 s | 0.0000003 s | sehr gross | Ohne Cache berechnet der Aufrufbaum dieselben Teilprobleme tausendfach, mit Cache jedes genau einmal | | 4 Arbeit aus der Schleife | 0.0877 s | 0.00025 s | ~350 | ''sorted'' lief 2000-mal mit identischer Eingabe und identischem Ergebnis | ===== Code ===== # 1 gesperrt = {f"user{i}" for i in range(10000)} # geschweifte statt eckige Klammern # 2 def zuordnen(bestellungen, kunden): index = {k["id"]: k for k in kunden} return [(index[b["kunde_id"]]["name"], b["betrag"]) for b in bestellungen] # 3 from functools import cache @cache def fibonacci(n): return n if n < 2 else fibonacci(n - 1) + fibonacci(n - 2) # 4 def top_drei_pro_kunde(kunden, produkte): top = [p["name"] for p in sorted(produkte, key=lambda p: p["preis"])[:3]] return {k["name"]: list(top) for k in kunden} ===== Fallen in dieser Aufgabe ===== * **Massnahme 2:** Die Vorher-Version behält die Reihenfolge der Bestellungen. Die Index-Version auch - aber nur, weil über ''bestellungen'' iteriert wird. Wer über ''kunden'' iteriert, bekommt eine andere Reihenfolge und damit ein anderes Ergebnis. * **Massnahme 3:** ''@cache'' funktioniert nur bei pure functions mit hashbaren Argumenten. Eine Liste als Argument wirft ''TypeError: unhashable type''. * **Massnahme 4:** ''list(top)'' statt ''top'' - sonst teilen sich alle 2000 Kunden **dieselbe** Liste. Solange niemand sie verändert, fällt das nicht auf; sobald doch, ändern sich alle Einträge gleichzeitig. Das ist der Referenz-Effekt aus [[modul:m323:learningunits:lu02:byvaluebyreference|LU02d]]. * **Ohne ''assert'' ist keine Messung gültig.** Eine schnellere Funktion mit anderem Ergebnis ist keine Optimierung, sondern ein Bug. ===== Zum Weiterdenken ===== Massnahme 1 kostet Speicher: Das Set legt zusätzlich zur Liste eine Hash-Tabelle an. Bei 10'000 Einträgen ist das irrelevant, bei 50 Millionen nicht. Diese Abwägung - Zeit gegen Speicher - ist genau das, was auf Niveau **D1A** begründet werden muss. ---- {{tag>M323-LU07 M323-D1I}} [[https://creativecommons.org/licenses/by-nc-sa/4.0/ch/|{{https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png}}]] (c) Kevin Maurizi