Технологам моей фирмы часто приходится писать 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