Optimalizácia práce s cache
- tomolas
- Člen | 66
Zdravím,
pracujem s trochu staršou verziou Nette: 2.0-dev (revision a8e74c1 released on
2010–10–14)
s cache sa hrám len veľmi krátko.
Riešim v tomto asi úplnú klasiku: cache-ovanie url tvorených
z databázy.
Robím to zatiaľ takto (ilustrácia kódu):
<?php
class MyRouting{
public static function getUrlById($id){
$storage = new Nette\Caching\FileStorage(TEMP_DIR);
$cache = new Cache($storage);
$urls = $cache->getStorage()->read('urls'); // je v cache zaznam ??
if(empty($urls[$id])){ // ak nie, citame z DB
$title = dibi::query("SELECT title FROM [pages] WHERE id=%i", $id)->fetchSingle();
$title = Nette\String::webalize($title);
$urls[$id] = $id.'-'.$title;
$cache->save('urls', $urls); // ulozime ziskane url z databazy do cache
}else{
// mame to z cache = je to ok
}
return $urls[$id];
}
}
?>
Mám ale dojem, že to nerobím dobre. Ak to chápem správne, tak volaním $cache->getStorage()->read(‚..‘) reálne čítam zo súboru a $cache->save(‚..‘) zapisujem. Jedná sa o desiatky až stovky volaní pri jednom behu.
Chcel by som to vyriešiť tak, že niekde pri štarte si súbor so zapísanými (v minulosti vygenerovanými) url 1× prečítam do premennej, potom s tým pracujem ako s premennou (prípadne za behu niečo pridám) a ak sa niečo zmenilo, premennú znova zapíšem do súboru.
Ak toto riešiť s použitím Environment a cache? Z dokumentácie som sa dostal do tohto stavu, ale myslím, že to musí ísť nejak rozumnejšie.
Ďakujem
Editoval tomolas (6. 10. 2011 11:58)
- tomolas
- Člen | 66
Ďakujem veľmi pekne.
Je to síce krásna ukážka, ale ide do ešte väčšej abstkrakcie. Ja som
skôr chcel pochopiť, ako čo najprimitívnejšie vyriešiť problém
viacnásobného čítania súboru. Resp. kam mám dať $cache = new Cache, aby
to bolo čo najrýchlejšie.
V tom príklade o niečom takom nie je reč.
Aj tak ďakujem za pomoc.
- Panda
- Člen | 569
Osobně bych to vyřešil asi takto:
Pozor, kód je psaný pro aktuální verzi Nette, základní myšlenka je
však stejná.
<?php
class MyRouting
{
/** @var \Nette\DI\IContainer */
private $container;
/** @var \Nette\Caching\Cache */
private $cache;
/** @var array Lokální cache na URL. */
private $urlList;
public function __construct(\Nette\DI\IContainer $container)
{
$this->container = $container;
}
protected function getCache()
{
if ($this->cache === NULL) {
$this->cache = new \Nette\Caching\Cache($this->container->cacheStorage);
}
return $this->cache;
}
public function getUrlById($id)
{
if ($this->urlList === NULL) {
$cache = $this->getCache();
if (isset($cache['urlList']) {
$this->urlList = $cache['urlList'];
} else {
$this->urlList = array();
}
if (!isset($this->urlList[$id])) {
$title = dibi::query('SELECT [title] FROM [pages] WHERE [id] = %i', $id)->fetchSingle();
$this->urlList[$id] = $id . '-' . \Nette\Utils\Strings::webalize($title);
$cache->save('urlList', $this->urlList);
}
}
return $this->urlList[$id];
}
}
?>
Cache se vytváří i čte skutečně jen jednou a to vždy v situaci, kdy je skutečně potřeba (lazy-loading). Zápis bude probíhat i vícekrát, ale předpokládám, že to zas takový problém nebude. Pokud bys i vícenásobné zápisy chtěl eliminovat, tak vždy při zjištění neexistence ID načti celou tabulku:
<?php
if (!isset($this->urlList[$id])) {
$list = dibi::query('SELECT [id], [title] FROM [pages]');
foreach ($list as $page) {
$this->urlList[$id] = $page->id . '-' . \Nette\Utils\Strings::webalize($page->title);
}
$cache->save('urlList', $this->urlList);
}
?>