Blog JSystems - uwalniamy wiedzę!

Szukaj
Optymalizacja funkcji z użyciem cache funkcji
Animacja lru_cache - zapamiętywanie wyników
lru_cache (memoizacja) - ten sam argument liczony raz, potem oddawany z pamięci

Przeanalizujmy poniższy przykład:

from datetime import datetime
import time

def czekacz():
    time.sleep(1)
    return 1

poczatek=datetime.now()
for x in range(10):
    czekacz()
koniec=datetime.now()
print(koniec-poczatek)

Mam funkcję "czekacz" której jedynym zadaniem jest poczekanie 1 sekundy i zwrócenie liczby 1. Funkcja ta jest wykonywana dziesięciokrotnie, a na koniec wypisywany jest czas realizacji całości. Kod w powyższym stanie wykonuje się nieco ponad 10 sekund. Przyjmijmy teraz że zamiast oczekiwania 1 sekundy mamy do wykonania jakieś złożone obliczenie które trwa. Jeśli funkcja dla danego outputu daje nam zawsze ten sam wynik (jest deterministyczna) to wynik tej funkcji można umieścić w cache i ponownie jej reużyć przy ponownym wywołaniu funkcji z tą samą wartością dla niej zamiast obliczać po raz wtóry. Do tego służy moduł "functools" i zawarty w nim dekorator "lru_cache". Przeanalizujmy teraz ten przykład po pewnych zmianach. Nad funkcją czekacz wpisałem dekorator "@functools.lru_cache". Dekorator ten sprawia że wynik działania naszej funkcji czekacz ląduje w cache i jest pobierana przy kolejnych wywołaniach tej funkcji dla tych samych argumentów (w naszym przypadku brak argumentu - funkcja zawsze zwraca 1):

from datetime import datetime
import time
import functools
@functools.lru_cache(maxsize=None)
def czekacz():
    time.sleep(1)
    return 1

poczatek=datetime.now()
for x in range(10):
    czekacz()
koniec=datetime.now()
print(koniec-poczatek)

Tym razem wykonanie całości zajeło nieco ponad 1 sekundę! Wynika to z tego, że kolejne wywołania tej funkcji odczytywały wartość z cache nie wykonując tej funkcji. Argument tego dekoratora (maxsize=None) określa dla ilu wartości wejściowych funkcja ma przechowywać dane w cache.

Cache można stosować tylko do funkcji deterministycznych - czyli w skrócie takich które dla tych samych parametrów wejściowych zwrócą nam zawsze te same dane wyjściowe.

Szkolenie Python od podstaw, przez analizę danych, do machine learning w JSystems

Ten kurs daje Ci solidne podstawy Pythona. Jeśli chcesz pójść dalej i pod okiem trenera dojść od pierwszej linijki kodu do własnego modelu uczenia maszynowego, sprawdź nasze pięciodniowe szkolenie Python od podstaw, przez analizę danych, do machine learning. Pierwsze trzy dni to Python w praktyce: typy i kolekcje, instrukcje warunkowe i pętle, funkcje, moduły i pakiety, pliki tekstowe, usługi sieciowe oraz praca z bazą PostgreSQL. Czwarty dzień to analiza danych w pandas (wczytywanie CSV, TSV i XLS, filtrowanie, agregacje, statystyki) i wizualizacja w Matplotlib, Seaborn oraz Plotly. Piąty dzień to uczenie maszynowe w scikit-learn: regresja liniowa i logistyczna, drzewa decyzyjne, las losowy, XGBoost, walidacja predykcji, dobór hiperparametrów i przeciwdziałanie przeuczeniu. Szkolenie ma terminy gwarantowane, czyli odbywa się niezależnie od wielkości grupy.

Szkolenie Python od podstaw, przez analizę danych, do machine learning

To szkolenie może być dofinansowane dla Ciebie z KFS lub BUR.

★★★★★Średnia ocena naszych szkoleń w Google: 5/5

Najczęściej zadawane pytania

Do czego służy dekorator lru_cache w Pythonie?
lru_cache to dekorator z modułu functools, który zapamiętuje wynik funkcji dla danych argumentów. Przy kolejnym wywołaniu z tymi samymi argumentami wynik jest oddawany z pamięci, zamiast liczony ponownie. To technika zwana memoizacją.
Kiedy mogę bezpiecznie użyć cache do funkcji?
Cache stosuj tylko do funkcji deterministycznych, czyli takich, które dla tych samych argumentów wejściowych zawsze zwracają ten sam wynik. Jeśli funkcja odczytuje zmienny stan albo zwraca coś losowego, memoizacja da błędne wyniki.
Co oznacza argument maxsize w lru_cache?
Argument maxsize określa, dla ilu różnych zestawów argumentów funkcja przechowuje wyniki w pamięci. Ustawienie maxsize=None oznacza brak limitu, czyli cache będzie rósł bez ograniczeń. Mniejsza wartość ogranicza zużycie pamięci.
Jaką realną oszczędność czasu daje cache w przykładzie z artykułu?
W przykładzie funkcja czekała 1 sekundę i była wołana dziesięć razy. Bez cache całość trwała nieco ponad 10 sekund, a z dekoratorem lru_cache tylko nieco ponad 1 sekundę, bo kolejne wywołania czytały wynik z pamięci.
Czy cache pomoże, jeśli funkcja za każdym razem dostaje inne argumenty?
Nie pomoże, bo memoizacja przyspiesza tylko powtarzalne wywołania z tymi samymi argumentami. Jeśli każde wywołanie ma unikalne dane wejściowe, wynik nigdy nie zostanie odczytany z pamięci i całość policzy się od nowa.

Komentarze (0)

Musisz być zalogowany by móc dodać komentarz. Zaloguj się przez Google

Brak komentarzy...