Cachowanie funkcji – przyspieszenie generowania stron

Kontynuując cykl optymalizacji aplikacji przedstawiam wam moja super klasę cachowania.
Przyspiesza ona generowanie stronek dość istotnie.
Wyobraźmy sobie system informatyczny, serwis www czy też inne ustrojstwo,
zawsze w każdej aplikacji jest chociażby jedna funkcja, która jest często
wywoływana i jej wykonanie zajmuje więcej czasu niż 0.05 sek, a jej wynik
zmienia się dość rzadko, np raz na godzinę. Czemu więc by nie wykonać
optymalizacji takiej funkcji? A co jeżeli bardziej się nie da? I tutaj
właśnie przedstawiam rozwiązanie :).

Po co?

Często mamy sytuację kiedy pewnych procesów nie da się zoptymalizować, np.:
proste zapytania do baz danych, odczytywanie plików, zewnętrznych zasobów itp.
Te procesy są uruchamiane często przez wiele osób, np 5 razy na minutę, 300 na godzinę,
a wynik tego procesu zmienia się nie częściej niż raz na godzinę.
Tutaj właśnie ma zastosowanie moja metoda cachowania :)

Na czym to polega

      Ładujemy cache.class.php
      Na początku funkcji którą chcemy cachować,
      nadajem unikalny znacznik, np “MenuList”.
      Następnie sprawdzamy czy istnieje cache dla tego słowa kluczowego
      Jeżeli tak – to wyciągamy dane z cache i od razu zwracamy wynik.
      Jeżeli nie – funkcja się ładnie wykonuje po czym przed samym zwracaniem
      wyniku do clasy Cache, są przesyłane dwie informacje: słowo klucz, wynik
      Funkcja zwraca wynik.

Ok to tak w skrócie i teorii, poniżej wklejam dwa kody źródłowe do analizy :)

index.php

Ten plik wywołuje funkcję getMenu(), która wykonuje się minimum 2 sek :),
więc ją przyśpieszmy.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?                                                                                      
require 'cache.class.php';                                                              

function getMenu(){
        $cacheName = 'MenuList';
                               
        if(Cache::is($cacheName))
            return Cache::get($cacheName);
                                         
        sleep(2);                        
        $result = array('home', 'contact');
        Cache::save($cacheName, $result);  
        return $result;                    
}                                          
function getmicrotime(){                  
    list($usec, $sec) = explode(" ",microtime());
    return ((float)$usec + (float)$sec);        
}                                                
                                                                       
$time_start = getmicrotime();                                          
$menu  = getMenu();                                                    
$time_end = getmicrotime();                                            
$time = $time_end - $time_start;                                        
echo $time;                                                            
?>

cache.class.php

Klasa odpowiedzialna za cachowanie, istnieją tutaj dwie zmienne
konfiguracyjne, pierwsza odpowiada za katalog gdzie ma być przechowywany cache
drugi mówi o ważności cacha.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?                                                                            
define('CACHE_DIR', '/tmp/cache/');                                          
define('CACHE_LIVE', 10);                                                    
class Cache{                                                                  


        function is($name){
                $r = false;
                $fileName = CACHE_DIR.MD5($name);
                if(is_file($fileName)){          
                    if( (filemtime($fileName)+CACHE_LIVE) > time())
                        $r = true;                                
                }                                                  
                return $r;                                        
        }                                                          
        function save($name, $content){                            
                file_put_contents(CACHE_DIR.MD5($name), serialize($content));
        }
        function get($name){
                return unserialize(file_get_contents(CACHE_DIR.MD5($name)));
        }
        function clear($name){
            unlink(CACHE_DIR.MD5($name));
        }
}

Nie wykorzystana metoda to clear() – ją wykorzystuję w momentach kiedy inna
procedura ma wpływ na właśnie cachowaną, np.: jeżeli cachujemy funkcję getMenu,
która ma identyfikator “MenuList”, a w innej części aplikacji wykonujemy
aktualizację zasobów mających wpływ na wynik getMenu(), wywołujemy w niej
metodę Cache::clear(’MenuList’). Kolejne wywołanie getMenu() spowoduje wykonanie
cache na nowo :)

Podsumowanie

Powyższych kodów nie ma sensu abym opisywał – widać co one robią.
Pierwsze uruchomienie skryptu index.php powinno pokazać wynik
conajmniej dwie sekundy, następne mniej jak 0,0002 :).
Tutaj właśnie następuje to cachowanie. Można to zastosować do wszelkich procesów,
które są często uruchamiane i zawsze zwracają ten sam wynik, przynajmniej przez
jakiś określony czas.

Wykorzystuję ten prosty algorytm w wielu moich aplikacjach, serwisach itp. Gorąco polecam!

 

Tagi: ,

Komentarze: 3 do “Cachowanie funkcji – przyspieszenie generowania stron”

  1. 1 mysql tabele tymczasowe at Mateusz Żeromski - Blog

    [...] Link do wspomnianego cache http://blog.zeromski.com.pl/2008/11/07/cachowanie-funkcji-przyspieszenie-generowania-stron/. [...]

  2. 2 A.Mazur

    A po cholerę MD5() nie wystarczy aby plik nazywałby się jak $name.

  3. 3 Mateusz Żeromski

    ano po to aby nie było ograniczenia w podawaniu nazwy cache – dzięki zaszyfrowaniu md5() możesz podać dowolną $name. Czasem może być że $name będzie się równało npo.: acasc/asc/asc/’;’sac[pasc, a jak wiadomo pliki lubią być nazywane alfanumerycznie. Dzięki md5 mam problem z głowy.

Napisz komentarz