Технологам моей фирмы часто приходится писать php-скрипты которые требуют большого времени выполнения. Многих php-кодеров такая задача как ни странно ставит в тупик, и сводится для них к оптимизации программы, или увеличения time-limit его запуска в апаче например. Тем ни менее никакая оптимизация не поможет если вам необходимо перегенерить тысячу превьюшек к фотографиям каталога магазина. Существуют пара на мой взгляд очевидных способов запускать такие скрипты.
Запуск командой через SSH
Это самый быстрый способ. Скрипт запущенный в командной строке сервера выполняется гораздо быстрее чем скрипт запущенный через Apache. Это как раз особенно заметно на генерации тысячи превьюшек.
В данном случае у вас может немного измениться местоположение папок и файлов если вы ведёте в скрипте запись в файлы. Это может быть тогда когда каталог запуска скрипта не совпадает с каталогом самого скрипта. Вам может помочь добавление такой строчки в начало вашего файла.
chown(realpath(___FILE___));
Запуск через Cron
Это примерно то же что и прямым вызовом команды php в ssh. Иногда доступа к ssh хостинг может не предоставлять, иногда в ssh может быть запрещён запуск php (по совершенно непонятным причинам как на хостинге J***.ru, хотя они обещают разрешить). Но запуск скриптов через крон как правило присутствует и в нём php тоже запускается. Например когда мы скачивали главные страницы всех сайтов рунета (2000000 штук) каждый десятый сайт наровил отнять минуту на загрузку, поэтому запуск такого скрипта в ssh был затянут надолго. Скачивая по пять сайтов в секунду кроном мы смогли скачать весь рунет всего за неделю. =)
Принцип запуска приложений в кроне почти такой же как и в ssh, за одной деталью: напишите свой скрипт так чтобы он запускался в один цикл, как для ssh... после этого сделайте перед началом цикла запись в файл номера позиции на которой вы остановились, а в первой строке цикла проверку на эту позицию. Например запись позиции при скачивании рунета мы осуществляли такой функцией
// int: going to update last users counter script since aborting a write because a file is locked is not correct.
function ifile($filename,$plus=1){
clearstatcache();
ignore_user_abort(true); ## prevent refresh from aborting file operations and hosing file
if (file_exists($filename)) {
$fh = fopen($filename, 'r+');
while(1) {
if (flock($fh, LOCK_EX)) {
$buffer = chop(fread($fh, filesize($filename)));
$buffer+=$plus;
rewind($fh);
fwrite($fh, $buffer);
fflush($fh);
ftruncate($fh, ftell($fh));
flock($fh, LOCK_UN);
break;
}
}
}
else {
$fh = fopen($filename, 'w+');
fwrite($fh, $plus);
$buffer=$plus;
}
fclose($fh);
return $buffer;
}
Использовать её нужно примерно так:
$my_position=ifile('counter.txt');
foreach($something as $i=>$tmp){
if($i<$my_position)continue;
/// делаем что-то c $tmp
die();
}
Запуск через Apache
Да, да, во-многих случаях запустить скрипт через Apache быстрее чем дождаться пока выполниться крон, тем более когда нужно увидеть возвращаемые ошибки.
Принцип запуска примерно такой же как в кроне, т.е. запускать каждый этап скрипта отдельно. Если у вас есть цикл который целиком никак не влазиет в time-limit веб-сервера, но который вполне можно выполнить за несколько раз сделайте такое-же добавление к коду как для Cron выше, и после каждого выполнения действий с элементом цикла вызывайте такую функцию:
function meta_page_refresh($url,$time=0){
if($time<0)$time=0;
echo 'META REFRESH
<meta http-equiv="refresh" content="'.$time.';url='.$url.'">
';
}
В данном случае вы можете обойтись без записи позиции в файл, а просто передавать её параметром $_GET, например так:
$i=(int)$_GET['num'];
meta_page_refresh('index.php?num='.($i+1)));
Вот и все секреты на сегодня. Следите за обновлениями через RSS.


Комментарии:
svoloch
23.11.2009 18:07:46
Moony (Елена Лунная)
23.11.2009 23:39:52