Доброго времени суток.
Работаю над проектом (PHP), в котором практически все операции происходят над файлами и каталогами — чтение, сканирование, вывод дерева и т.д.
Иногда для создания иерархичного дерева каталога (в смысле, с его подкаталогами) нужно больше 6 секунд (со временем время уменьшается до 3, видимо, кэшируются данные о файлах), что сильно тормозит работу.
Возникла идея кэширования результатов выполнения некоторых функций (тех, что связаны со сканированием подкаталогов) для уменьшения времени выполнения и нагрузки на процессор & хард ценой дискового пространства и оперативной памяти (имхо, 500 кб на харде лучше, чем 6 секунд ждать).
Базу данных не использую (для файлов считаю лишним), поэтому даже не думаю использовать ее в целях оптимизации.
Для реализации идеи написал класс:
<?php
class Cacher {
// Класс для кэширования данных между скриптами
// Применять к динамическим данным не рекомендуется
// Сэкономит время при вызове функций, которые выполняются
// более 10мс.
// Принцип действия:
// Данные выполнения функции кэшируются в файл и в переменную класса
// Если функция будет вызвана в том же скрипте второй (и больше) раз
// с теми же параметрами, она сразу вернет данные из кэша
// Если функция вызвана с какими-то параметрами впервые в скрипте,
// произойдет проверка на существование файла с кэшем и будет возвращено
// содержимое файла
//
// Использование:
// 1. Создать объект класса / прописать для своего класса extends Cacher
// 2. Вызвать Cacher->CacheInit(string cache_dir, string prefix), где указать полный путь
// к каталогу для кэширования и префикс (опционально, желательно для классов)
// 3. В начале стабильных функций написать
// /* c */ if($this->IsCached('myfunc')){ return $this->GetCache('myfunc'); }
// где myfunc - имя ячейки кэша (желательно имя функции)
// 4. Перед отдачей (return) в функции прописать
// /* c */ $this->Cache('myfunc', $ret);
// где $ret - результат выполнения функции
public $cache = array();
public $cache_dir;
public $prefix;
public $enabled = false;
function CacheInit($cache_dir, $prefix=''){
if(!is_dir($cache_dir)){
mkdir($cache_dir);
}
$this->cache_dir = $cache_dir;
$this->prefix = $prefix;
$this->enabled = true;
}
function Cache($function, $data){
if(!$this->enabled){ return false; }
$this->cache[$function] = $data;
file_put_contents($this->cache_dir.$this->prefix.$function,serialize($data));
}
function GetCache($function){
if(!$this->enabled){ return false; }
return $this->cache[$function];
}
function IsCached($function){
if(!$this->enabled){ return false; }
if(isset($this->cache[$function])){
return true;
}elseif(is_file($this->cache_dir.$this->prefix.$function)){
$this->cache[$function] = unserialize(file_get_contents($this->cache_dir.$this->prefix.$function));
return true;
}else{
return false;
}
}
function ClearCache($function){
if(!$this->enabled){ return false; }
if(is_array($function)){
foreach($function as $unit){
@unlink($this->cache_dir.$this->prefix.$unit);
}
}else{
@unlink($this->cache_dir.$this->prefix.$function);
}
$this->cache = array();
}
}
?>
Использовал так:
<?php
class SomeClass extends Cacher {
function __construct(){
// Включаем кеширование
$this->CacheInit(ROOT.'/_cache/vcs/');
// ...
}
function ScanDir($path=''){ // Этим будем вытаскивать дерево каталогов
/* c */ $_c = 'ul('.str_replace('/','_slh_',$path.')';
/* c */ if($this->IsCached($_c)){ return $this->GetCache($_c); }
$return = array();
$src = opendir($path);
while($obj = readdir($src)){
if(is_dir($path.'/'.$obj)){
$return = array_merge($return, $this->ScanDir($path.'/'.$obj)); // Глубокая рекурсия
}else{
$return[] = $path.'/'.$obj;
}
}
closedir($src);
/* c */ $this->Cache($_c, $return);
return $return;
}
}
$Obj = new SomeClass();
$Obj->ScanDir();
Пробовал профилировать выполнение с / без «кэширования» в боевых условиях, результат боевых действий (повторные запросы):
Без «кэширования»: 3.1829 с.
С «кэшированием»: 0.0097 с. +420кб на харде
Вопрос к знатокам: в чем может быть подвох, и оправдан ли такой подход (если кто-то с таким сталкивался), если при изменении файлов / каталогов удалять определенные «ячейки кэша» (удалять файлы)