Lru și fifo cache-uri în scală fără dependențe inutile, note de programator

O aplicație serioasă serioasă în aceste zile se face fără a cache nimic. Unele cache-uri LRU sunt implementate elementar, de exemplu, folosind tabelele hash și listele duble asociate. Dar nu este un fapt că decizia dvs. va fi foarte eficientă, deci este mai bine să utilizați implementarea finalizată. Adesea, Guava sau LruMap din twitter-util este recomandat ca o astfel de implementare. Dar aceste soluții au dezavantajele lor, în special, stiva de Twitter se leagă în mod tradițional de Scala 2.10, iar Guava este pur și simplu teribilă.







Din fericire, în Scala, puteți să creați cu ușurință o memorie cache simplă fără a deplasa și aluneca dependențe în proiect. În lumea Java, este bine cunoscut faptul că primim cu suprascrierea metodei removeEldestEntry a clasei LinkedHashMap, care permite obținerea unei cache-uri LRU. Recepția nu este prea elegantă, dar nu este la fel de înfricoșătoare ca Guava. Tradus în Scala, arată astfel:

import java. UTIL. # 123; Harta, LinkedHashMap # 125;

def makeCache # 91; K, V # 93; # 40; capacitate. Int # 41;. hartă # 91; K, V # 93; = # 123;
noul LinkedHashMap # 91; K, V # 93; # 40; capacitate, 0.7F, adevărat # 41; # 123;
private val cacheCapacity = capacitate

suprascrie def removeEldestEntry # 40; intrare. Harta. intrare # 91; K, V # 93; # 41;. Boolean = # 123;
acest lucru. dimensiune # 40; # 41;> acest lucru. cacheCapacity
# 125;
# 125;
# 125;

scala> caz de clasă câine (nume: șir)
categorie de câine definită

scală> val cache = makeCache [String, Dog] (3)
cache: java.util.Map [String, Dog] = <>

scală> Opțiunea (cache.get ("8"))
Res2: Opțiunea [Dog] = Unele (câine (8))

scală> Opțiunea (cache.get ("ololo"))
Res4: Opțiunea [Dog] = Niciuna

Rețineți că cache.get se înfășoară în jurul Opțiunii, deoarece este un LinkedHashMap jaded și metoda get poate reveni la null. Dar pentru tipurile primitive (Int și altele asemănătoare), valoarea implicită este returnată:







scală> val cache = makeCache [String, Int] (3)
cache: java.util.Map [String, Int] = <>

scala> cache.get ("test")
res5: Int = 0

scală> val cache = makeCache [String, Boolean] (3)
cache: java.util.Map [String, Boolean] = <>

scala> cache.get ("test")
res6: Boolean = false

Prin urmare, este posibil să doriți să utilizați metoda conțineKeyKey:

scala> cache.containsKey ("test")
res7: Boolean = false

Ar trebui, de asemenea, să ia în considerare faptul că în cazul în care keshom dvs. poate rula mai mult de un flux la un moment dat, va trebui să-l înveliți în synchonized:

scala> cache.synchronized
res8: Boolean = false

Acum ia în considerare a doua metodă.

Scala are, de asemenea, un LinkedHashMap, dar nu are un argument accessOrder, ca într-un LinkedHashMap blocat, care poate fi folosit doar pentru a obține o memorie cache FIFO:

scala de import. de colectare. _

val cacheCapacitate = 10000
val cacheMutex = Obiect nou # 40; # 41;
var cache = mutable. LinkedHashMap # 91; String, lung # 93; # 40; # 41;

// scrieți în memoria cache
cacheMutex. sincronizate # 123;
cache. pune # 40; „Cheia“. 100500 # 41;
cache = cache. picătură # 40; cache. dimensiune - cacheCapacitate # 41;
# 125;

// citiți din memoria cache
cacheMutex. sincronizate # 123; cache. obține # 40; „Cheia“ # 41; # 125;

Aici metoda get returnează o opțiune. Cache-ul este resetat manual folosind metoda drop. Și această metodă returnează un nou LinkedHashMap, astfel încât pentru a sincroniza accesul în memoria cache, este necesar un obiect separat cacheMutex. De asemenea, trebuie să țineți cont de faptul că, din motive de eficiență, este posibil să doriți să faceți o picătură nu la fiecare intrare din memoria cache:

// scrieți în memoria cache
cacheMutex. sincronizate # 123;
cache. pune # 40; „Cheia“. 100500 # 41;
dacă # 40; cache. dimensiune> cacheCapacitate # 41; # 123;
cache = cache. picătură # 40; cache. dimensiune - # 40; cacheCapacity. toDouble * 0.75 # 41;. toInt # 41;
# 125;
# 125;

Și, în general, poate o faceți într-un fir separat.

Inutil să spun, există multe alte modalități de a crea un cache la Scala, dar cei doi mi se par cele mai simple. Desigur, în aplicații reale este mult mai interesant, deoarece cache-urile nu trebuie să se despartă de date reale sau cache-uri de pe alte cache nodah poate fi necesar să fie împărțită în mai multe, astfel încât să nu devină o problemă, și așa mai departe.

Și cum faceți cache-uri?







Trimiteți-le prietenilor: