Caching to termin używany w informatyce. Idea cache'a (wymawiane "gotówka" /ˈkæʃ/ KASH) jest prosta: często uzyskanie lub wygenerowanie pewnych danych jest czasochłonne lub kosztowne, więc zamiast za każdym razem powtarzać kosztowną operację, przechowuje się jej wynik w miejscu, do którego dostęp jest znacznie szybszy. W praktyce używa się dwóch klas nośników danych: jeden jest zwykle duży, lecz „powolny” (np. dysk twardy, pamięć masowa sieciowa), drugi jest mniejszy, ale dużo szybszy (np. pamięć SRAM w procesorze, pamięć RAM jako bufor). Podstawową ideą jest przechowywanie kopii często używanych fragmentów danych w szybkim nośniku — pamięci podręcznej. Kopia nie różni się semantycznie od oryginału, ale dostęp do niej jest zwykle szybszy lub tańszy czasowo, co zmniejsza średni czas potrzebny na odczyt danych.
Jak działa pamięć podręczna (cache)
Pamięć podręczna trzyma fragmenty danych (zwykle zorganizowane w tzw. bloki lub linie cache). Gdy system żąda pewnego bloku, najpierw sprawdzana jest pamięć podręczna — jeśli blok tam jest (tzw. cache hit), dostęp jest szybki. Gdy go nie ma (tzw. cache miss), blok trzeba pobrać z wolniejszego nośnika i często umieścić go w cache, co może wymagać usunięcia innego bloku (tzw. eviction).
Lokalność odniesienia
Skuteczność cache'a opiera się na dwóch rodzajach lokalności:
- Temporalna — jeśli dany blok był użyty niedawno, istnieje duże prawdopodobieństwo, że będzie użyty ponownie;
- Przestrzenna — dostęp do pewnego bloku często oznacza, że nastąpi dostęp do bloków „bliskich” mu logicznie lub adresowo.
Te właściwości powodują, że nawet mała pamięć podręczna poprawia średnią wydajność dostępu do danych. W tekście pierwotnym wspomniano lokalizację odniesienia — to właśnie opisane wyżej zasady lokalności.
Rodzaje cache i przykłady zastosowań
- Pamięć cache procesora (L1, L2, L3) — najmniejsze i najszybsze, trzyma instrukcje i dane najczęściej używane przez CPU.
- Cache dyskowy / systemu plików — RAM używany do buforowania odczytów/zapisów z dysku, przyspiesza operacje we/wy.
- Przeglądarki i CDN — przechowują kopie stron i zasobów, zmniejszając opóźnienia i obciążenie sieci.
- Cache DNS — przechowuje ostatnio rozwiązane nazwy domen, skracając czas odpowiedzi.
- Cache aplikacyjne i bazy danych — np. pamięci podręczne w pamięci (Redis, Memcached) przyspieszają odczyty często używanych rekordów.
Strategie zastępowania (eviction)
Gdy trzeba wstawić nowy blok do pełnego cache'a, wybiera się blok do usunięcia według określonej strategii:
- LRU (Least Recently Used) — usuwa się element najmniej niedawno używany;
- FIFO (First In, First Out) — usuwa się najstarszy wpis;
- LFU (Least Frequently Used) — usuwa się element z najmniejszą liczbą użyć;
- Random — usuwa się losowy wpis (czasem prostsze i wystarczające);
- oraz ich warianty i hybrydy (np. approximated LRU dla oszczędności pamięci).
Polityki zapisu (write policies)
W przypadku zapisu danych wyróżnia się m.in.:
- Write-through — zapis trafia jednocześnie do cache i do pamięci głównej (łatwe zapewnienie spójności, ale wolniejsze);
- Write-back — zapisuje się tylko w cache, a do pamięci głównej zmienione bloki są zapisywane później (wydajniejsze, ale wymaga oznaczania „brudnych” bloków i mechanizmów ich wypychania);
- Write-allocate vs no-write-allocate — decyzja, czy przy zapisie brakującego bloku najpierw wczytać go do cache, czy zapisać bezpośrednio do pamięci głównej.
Parametry projektowe
Podstawowe parametry cache'a to:
- rozmiar (ilość pamięci dostępnej na cache),
- rozmiar linii/bloku (jednostka przenoszona między pamięcią a cache),
- asocjacyjność (direct-mapped, set-associative, fully-associative) określająca, ile miejsc w cache może przechowywać dany blok adresowy),
- czas dostępu i przepustowość,
- współczynnik trafień (hit rate) i stawka błędów (miss rate) — kluczowe miary skuteczności.
Im większy cache, tym zwykle wyższy współczynnik trafień, ale też większy koszt fizyczny i — w niektórych konstrukcjach — dłuższy czas wyszukiwania wpisu. Stąd projektanci dobierają optymalny rozmiar i asocjacyjność dla danego zastosowania.
Spójność i problemy wieloprocesorowe
W systemach wielordzeniowych pamięci podręczne poszczególnych rdzeni mogą mieć kopie tych samych danych — konieczne są mechanizmy zapewniające spójność (cache coherence), np. protokoły MESI, aby uniknąć odczytów przestarzałych wartości.
Praktyczne uwagi i optymalizacje
- Dobór strategii zastępowania i parametrów zależy od wzorca dostępu do danych — LRU dobrze działa przy silnej lokalności temporalnej, LFU przy powtarzalnych wzorcach dostępu.
- Prefetching (wczytywanie kolejnych bloków przewidywanych do użycia) może zwiększyć trafienia przy przewidywalnych wzorcach.
- Cache warming — wstępne załadowanie często używanych danych po uruchomieniu systemu poprawia wydajność startową.
- W aplikacjach sieciowych warto pamiętać o mechanizmach unieważniania (cache invalidation) i czasie życia danych (TTL) — by nie serwować przestarzałych informacji.
Bufor a pamięć podręczna — różnice
Bufor i cache pełnią podobne role, ale różnią się celem i modelem użycia. Bufor (ang. buffer) służy zwykle do wyrównania prędkości między producentem a konsumentem danych (np. bufor dysku lub bufor sieciowy) i często jest jawnie zarządzany przez aplikację; klient może być świadomy istnienia bufora i korzystać z niego w określony sposób. Pamięć podręczna natomiast jest częściej mechanizmem transparentnym, którego celem jest przyspieszenie wielokrotnych odczytów poprzez przechowywanie kopii; klient zwykle nie musi explicitnie zarządzać cache'em ani wiedzieć o jego istnieniu.
Podsumowanie
Pamięć podręczna to uniwersalne narzędzie poprawiające wydajność systemów poprzez przechowywanie często używanych kopii danych w szybszym medium. Jej efektywność opiera się na lokalności odniesienia, odpowiednim doborze rozmiaru, asocjacyjności, polityk zapisu oraz strategii zastępowania. W praktyce cache występuje w wielu warstwach systemów komputerowych — od CPU, przez system plików, aż po warstwę aplikacyjną i sieciową — i jest jednym z najważniejszych mechanizmów optymalizacyjnych w informatyce.

