PHP скрипт с огромным временем выполнения — как правильно такое писать?

Приветствую всех хабровчан

Есть скрипт парсинга xml файла с последующей записью в базу и закачкой картинок по урлам из этого файла. Скрипт использует SimpleXML. Сразу оговорюсь что писал его не я, я лишь сейчас довожу его до состояния нужного нам дописывая необходимые вещи.
Проблема состоит в том что объем файла который мы парсим очень большой — 8000-8500 записей. Плюс на каждую запись от 3 до 5 картинок, которые он качает. В результате скрипт парсит гдето 6500 записей и дальше тихо останавливается. Я пытался запустить этот скрипт на хостинге где можно поднять максимальное время выполнения — помогает но не полностью — парсит гдето 7500-7800 записей и останавливается. Может есть еще какие-то ограничения которые надо поднимать?

Прошу подсказать мне про методики написания таких скриптов обрабатывающих болльшие объемы данных. Через cron его запустить не удасться — так как это расширение к одной из цмс.
Буду благодарен за любые мысли и идеи
  • Вопрос задан
  • 17206 просмотров
Пригласить эксперта
Ответы на вопрос 10
Igogo2012
@Igogo2012
Я оформлял такие скрипты в виде консольной команды на PHP.
И работало все по такому принципу:
1) Запускаем команду, она пишет в базу (в специальную табличку) что она запущена
2) На фронтенде запускается ajax который время от времени проверяет табличку с состоянием команды по ее идентификатору.
3) Команда завершилась ошибкой и записала в табличку свое состояние «error» например и сообщение ошибки, ajax запрос увидел это и сообщил уже веб интерфейсу.
4) Команда завершилась успехом — аналогично пункту (3)
Ответ написан
Комментировать
@MaxUp
а запускается как? В автоматическом режиме или человек запускает?
Если последнее — AJAX + использовать функцию register_shutdown_function(), что бы отловить момент прерывания задачи, возращать назад флаг, что импорт не закончен + номер последней записи. Повторять запросы в автоматическом режиме, пока задача не будет выполнена.
Ответ написан
CrazySquirrel
@CrazySquirrel
Я конечно понимаю, что такие советы давать когда софт уже написан не лучшая идея, но всё таки советую Вам расмотреть возможность распаралеливания процесса, например при помощи gearman, это увеличит производительность Вашего скрипта.
Ответ написан
Комментировать
@begemot_nn
если скрипт запускается из браузера (аяксом ли, или просто дерганием ссылки) не забыть поставить
ignore_user_abort(true);
Ответ написан
Комментировать
@rozhik
SAX парсер будет работать намного более экономно к памяти, и скорее всего много быстрее.
Ответ написан
Комментировать
Можно написать скрипт чтобы он парсил например по 100 записей и потом сохранял текущую позицию и перезапускался, начинал парсинг с сохраненной позиции.

Таким образом решите проблему с временем выполнения и всем остальным
Ответ написан
@lubezniy
Вот ещё хоть и извращенческо-костыльный, но в некоторых случаях почти незаменимый вариант (требуются базовые знания PHP и HTML/JavaScript):

1. Пишется скрипт, парсящий XML и составляющий в виде HTML табличку с урлами картинок.
2. Пишется скрипт, которому передаётся два параметра: значение строки в табличке из п. 1 и номер (индекс) строки в этой табличке. Задача скрипта: в PHP-части залить картинку и записать что надо в базу, а в onload на body (javascript) прописать редирект на себя же, но со значением (получается из javascript) и индексом следующей строки таблички. Если индекс равен количеству строк, выдать alert, что заливка закончилась.
3. Пишется простенькая html-страничка из двух фреймов: в первом фрейме скрипт из п. 1, во втором — скрипт из п. 2 со стартовыми значениями. Эта страничка открывается в браузере, после чего можно пойти поспать. Комп желательно держать на надёжном канале в инет и бесперебойнике, чтобы связь не прервалась.
Ответ написан
mihavxc
@mihavxc
У меня php скрипты запущенные фоном через cron иногда по неделе работают(работа со сторонним API + выкачивание картинок + запись в БД).

Обхожусь одним
set_time_limit(0);

Если не поможет посмотрите в логах вебсервера, возможно у вас БД отваливается из-за слишком долгой сессии. Ошибка будет примерно такая
MySQL server has gone away
Ответ написан
alekciy
@alekciy
Вёбных дел мастер
Качать картинки тем же скриптом совершенно не обязательно. Я обычно просто сохраняю url в файл который потом отдается wget-у (флаг -i). Бывает и так, что внешняя обвязка (CMS) сохраняет файлы в какой-то своей структуре. Поэтому для такого случая можно wget-ом картинки предварительно накачать в локальную ФС. Что бы в ФС адрес картинки был такой же, как у URL следует использовать -x опицию Вот типичный пример загрузки:

wget -x -b --user-agent="Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6" --referer="http://examplke.com/" -i img_url_list.txt

Качает очень быстро + легко параллелиться если разделить файл на куски и запускать с разных серверов. У меня с двух серверов 200 000 картинок общим объемом ~8ГБ грузиться около часа.
Ответ написан
Комментировать
@UTD
Использовал так:

set_time_limit(0);
ini_set('max_execution_time', 0);

вот так:

set_time_limit(0);

вот так:

set_time_limit(9000);

через какой-то время выдает 504 Gateway Time-out

как можно это побороть, что бы скрипт таки доделал свои функции за пределами времени и открыл обратно страницу без этой ошибки?

Или же можно как-то что бы он разбивал работу скрипта на парты, допустим в БД пишуться 15к строк, и что бы он при подходе к тайм ауту перезапускал счетчик тайм аута?
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы