Python-Cache-FimgPython-Cache-Fimg
Bild vom Autor

In Python können Sie Caching verwenden, um die Ergebnisse aufwändiger Funktionsaufrufe zu speichern und sie wiederzuverwenden, wenn die Funktion erneut mit denselben Argumenten aufgerufen wird. Dadurch wird Ihr Code leistungsfähiger.

Python bietet integrierte Unterstützung für das Caching durch die functools Modul: die Dekorateure @cache Und @lru_cache. Und wir werden in diesem Tutorial lernen, wie man Funktionsaufrufe zwischenspeichert.

Warum ist Caching hilfreich?

Das Zwischenspeichern von Funktionsaufrufen kann die Leistung Ihres Codes erheblich verbessern. Hier sind einige Gründe, warum das Zwischenspeichern von Funktionsaufrufen von Vorteil sein kann:

  • Leistungsverbesserung: Wenn eine Funktion mehrmals mit denselben Argumenten aufgerufen wird, kann das Zwischenspeichern des Ergebnisses redundante Berechnungen vermeiden. Anstatt das Ergebnis jedes Mal neu zu berechnen, kann der zwischengespeicherte Wert zurückgegeben werden, was zu einer schnelleren Ausführung führt.
  • Reduzierung des Ressourcenverbrauchs: Einige Funktionsaufrufe können rechenintensiv sein oder erhebliche Ressourcen erfordern (z. B. Datenbankabfragen oder Netzwerkanforderungen). Durch das Zwischenspeichern der Ergebnisse müssen diese Vorgänge nicht so oft wiederholt werden.
  • Verbesserte Reaktionsfähigkeit: Bei Anwendungen, bei denen die Reaktionsfähigkeit von entscheidender Bedeutung ist, wie etwa Webservern oder GUI-Anwendungen, kann das Caching zur Reduzierung der Latenz beitragen, indem wiederholte Berechnungen oder E/A-Vorgänge vermieden werden.

Kommen wir nun zum Codieren.

Caching mit dem @cache Decorator

Lassen Sie uns eine Funktion codieren, die die n-te Fibonacci-Zahl berechnet. Hier ist die rekursive Implementierung der Fibonacci-Folge:

def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

Ohne Zwischenspeicherung führen die rekursiven Aufrufe zu redundanten Berechnungen. Wenn die Werte zwischengespeichert werden, wäre es viel effizienter, die zwischengespeicherten Werte nachzuschlagen. Und dafür können Sie den @cache Dekorateur.

Der @cache Dekorateur aus dem functools Das Modul in Python 3.9+ wird verwendet, um die Ergebnisse einer Funktion zwischenzuspeichern. Es funktioniert, indem es die Ergebnisse teurer Funktionsaufrufe speichert und sie wiederverwendet, wenn die Funktion mit denselben Argumenten aufgerufen wird. Lassen Sie uns nun die Funktion mit dem @cache Dekorateur:

from functools import cache

@cache
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

Wir werden später auf den Leistungsvergleich eingehen. Sehen wir uns nun eine andere Möglichkeit an, Rückgabewerte von Funktionen mit dem @lru_cache Dekorateur.

Zwischenspeichern mit dem @lru_cache Decorator

Sie können die integrierte functools.lru_cache Dekorator auch für das Caching. Dies verwendet den Least Just lately Used (LRU)-Caching-Mechanismus für Funktionsaufrufe. Wenn beim LRU-Caching der Cache voll ist und ein neues Ingredient hinzugefügt werden muss, wird das am wenigsten zuletzt verwendete Ingredient im Cache entfernt, um Platz für das neue Ingredient zu schaffen. Dadurch wird sichergestellt, dass die am häufigsten verwendeten Elemente im Cache erhalten bleiben, während weniger häufig verwendete Elemente verworfen werden.

Der @lru_cache Dekorateur ist ähnlich wie @cache Sie können jedoch die maximale Größe festlegen, da die maxsize Argument – ​​des Caches. Sobald der Cache diese Größe erreicht, werden die zuletzt verwendeten Elemente verworfen. Dies ist nützlich, wenn Sie die Speichernutzung begrenzen möchten.

Hier das fibonacci Die Funktion speichert bis zu 7 zuletzt berechnete Werte im Cache:

from functools import lru_cache

@lru_cache(maxsize=7)  # Cache as much as 7 most up-to-date outcomes
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

fibonacci(5)  # Computes Fibonacci(5) and caches intermediate outcomes
fibonacci(3)  # Retrieves Fibonacci(3) from the cache

Hier das fibonacci Funktion ist dekoriert mit @lru_cache(maxsize=7)und geben Sie an, dass bis zu 7 aktuelle Ergebnisse zwischengespeichert werden sollen.

Wann fibonacci(5) heißt, die Ergebnisse für fibonacci(4), fibonacci(3)Und fibonacci(2) werden zwischengespeichert. Wenn fibonacci(3) wird anschließend aufgerufen, fibonacci(3) wird aus dem Cache abgerufen, da es sich um einen der sieben zuletzt berechneten Werte handelte, wodurch redundante Berechnungen vermieden werden.

Timing von Funktionsaufrufen zum Vergleich

Vergleichen wir nun die Ausführungszeiten der Funktionen mit und ohne Caching. Für dieses Beispiel setzen wir keinen expliziten Wert für maxsize. Additionally maxsize wird auf den Standardwert 128 gesetzt:

from functools import cache, lru_cache
import timeit

# with out caching
def fibonacci_no_cache(n):
    if n <= 1:
        return n
    return fibonacci_no_cache(n-1) + fibonacci_no_cache(n-2)

# with cache
@cache
def fibonacci_cache(n):
    if n <= 1:
        return n
    return fibonacci_cache(n-1) + fibonacci_cache(n-2)

# with LRU cache
@lru_cache
def fibonacci_lru_cache(n):
    if n <= 1:
        return n
    return fibonacci_lru_cache(n-1) + fibonacci_lru_cache(n-2)

Um die Ausführungszeiten zu vergleichen, verwenden wir die timeit„ Funktion aus dem timeit Modul:

# Compute the n-th Fibonacci quantity
n = 35  

no_cache_time = timeit.timeit(lambda: fibonacci_no_cache(n), quantity=1)
cache_time = timeit.timeit(lambda: fibonacci_cache(n), quantity=1)
lru_cache_time = timeit.timeit(lambda: fibonacci_lru_cache(n), quantity=1)

print(f"Time with out cache: {no_cache_time:.6f} seconds")
print(f"Time with cache: {cache_time:.6f} seconds")
print(f"Time with LRU cache: {lru_cache_time:.6f} seconds")

Die Ausführung des obigen Codes sollte zu einer ähnlichen Ausgabe führen:

Output >>>
Time with out cache: 2.373220 seconds
Time with cache: 0.000029 seconds
Time with LRU cache: 0.000017 seconds

Wir sehen einen deutlichen Unterschied in den Ausführungszeiten. Der Funktionsaufruf ohne Zwischenspeicherung dauert viel länger, insbesondere bei größeren Werten von n. Während die zwischengespeicherten Versionen (beide @cache Und @lru_cache) werden viel schneller ausgeführt und haben vergleichbare Ausführungszeiten.

Einpacken

Mithilfe der @cache Und @lru_cache Dekoratoren können Sie die Ausführung von Funktionen, die teure Berechnungen oder rekursive Aufrufe beinhalten, erheblich beschleunigen. Den vollständigen Code finden Sie auf GitHub.

Wenn Sie nach einem umfassenden Leitfaden zu Finest Practices für die Verwendung von Python für Knowledge Science suchen, lesen Sie 5 Python Finest Practices für Knowledge Science.

Bala Priya C ist Entwicklerin und technische Redakteurin aus Indien. Sie arbeitet gerne an der Schnittstelle zwischen Mathematik, Programmierung, Datenwissenschaft und Inhaltserstellung. Ihre Interessens- und Fachgebiete umfassen DevOps, Datenwissenschaft und natürliche Sprachverarbeitung. Sie liest, schreibt, programmiert und trinkt gerne Kaffee! Derzeit arbeitet sie daran, ihr Wissen zu lernen und mit der Entwickler-Group zu teilen, indem sie Tutorials, Anleitungen, Meinungsbeiträge und mehr verfasst. Bala erstellt auch ansprechende Ressourcenübersichten und Programmier-Tutorials.



Von admin

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert