Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

PHP — стоит ли применять кэширование итогов выполнения функций

Anna | 31.05.2014 | нет комментариев

Тружусь над планом (PHP), в котором фактически все операции происходят над файлами и каталогами — чтение, сканирование, итог дерева и т.д.
Изредка для создания иерархичного дерева каталога (в смысле, с его подкаталогами) необходимо огромнее 6 секунд (со временем время уменьшается до 3, видимо, кэшируются данные о файлах), что крепко тормозит работу.

Появилась идея кэширования итогов выполнения некоторых функций (тех, что связаны со сканированием подкаталогов) для уменьшения времени выполнения и нагрузки на процессор & хард ценой дискового пространства и оперативной памяти (имхо, 500 кб на харде отменнее, чем 6 секунд ожидать).

Базу данных не использую (для файлов считаю лишним), следственно даже не думаю применять ее в целях оптимизации.

Для реализации идеи написал класс:

<?php
class Cacher {

	// Класс для кэширования данных между скриптами
	// Использовать к динамическим данным не рекомендуется
	// Сэкономит время при вызове функций, которые выполняются
	// больше 10мс.
	// Правило действия:
	// Данные выполнения функции кэшируются в файл и в переменную класса
	// Если функция будет вызвана в том же скрипте 2-й (и огромнее) раз
	// с теми же параметрами, она сразу вернет данные из кэша
	// Если функция вызвана с какими-то параметрами впервой в скрипте,
	// произойдет проверка на существование файла с кэшем и будет возвращено
	// содержимое файла
	//
	// Применение:
	// 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кб на харде

Вопрос к знатокам: в чем может быть подвох, и оправдан ли такой подход (если кто-то с таким сталкивался), если при изменении файлов / каталогов удалять определенные «ячейки кэша» (удалять файлы)

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB