Лучший способ управлять продолжительным сценарием PHP?

У меня есть Сценарий PHP, который занимает много времени (5-30 минут) для завершения. На всякий случай это имеет значение, сценарий использует завихрение для очистки данных из другого сервера. Это - причина, она занимает много времени; это должно ожидать каждой страницы для загрузки прежде, чем обработать его и переместиться в следующее.

Я хочу смочь инициировать сценарий и позволить ему быть, пока он не сделан, который установит флаг в таблице базы данных.

То, что я должен знать, - то, как смочь закончить запрос HTTP, прежде чем сценарий будет закончен, работая. Кроме того, действительно ли сценарий PHP является лучшим способом сделать это?

75
задан kbanman 30 January 2015 в 04:03
поделиться

8 ответов

Конечно, это можно сделать с помощью PHP, однако НЕ следует делать это как фоновую задачу - новый процесс должен быть отделен от группы процессов, в которой он инициирован.

Поскольку люди продолжают давать одни и те же неправильные ответы на этот FAQ, я написал более полный ответ здесь:

http://symcbean.blogspot.com/2010/02/php-and-long-running-processes .html

Из комментариев:

Краткая версия - shell_exec ('echo / usr / bin / php -q longThing.php | at now'); , но причины, почему долго для включения здесь.

106
ответ дан 24 November 2019 в 11:37
поделиться

Можно использовать exec или system для запуска фонового задания, а затем выполнять работу в нем.

Кроме того, существуют лучшие подходы к соскребанию паутины, которые вы используете. Вы можете использовать потоковый подход (несколько потоков, делающих по одной странице за раз), или один с помощью петли событий (один поток, делающий несколько страниц за раз). Мой личный подход с использованием Perl будет заключаться в использовании AnyEvent::HTTP.

ETA: symcbean объяснил, как правильно отделить фоновый процесс здесь .

8
ответ дан 24 November 2019 в 11:37
поделиться

Быстрым и грязным способом было бы использование функции ignore_user_abort в php. В принципе, это говорит: Неважно, что делает пользователь, запустите этот скрипт, пока он не будет закончен. Это несколько опасно, если это публичный сайт (потому что возможно, что у вас будет 20++ версий скрипта, запущенного одновременно, если он будет инициирован 20 раз).

Чистый" способ (по крайней мере IMHO) заключается в установке флага (например, в db), когда вы хотите инициировать процесс и запускать cronjob каждый час (или около того), чтобы проверить, установлен ли этот флаг. Если он установлен, запускается длинный скрипт, если он НЕ установлен, ничего не происходит.

11
ответ дан 24 November 2019 в 11:37
поделиться

Вы можете отправить его как запрос XHR (Ajax). У клиентов обычно нет тайм-аута для XHR, в отличие от обычных HTTP-запросов.

1
ответ дан 24 November 2019 в 11:37
поделиться

Я проделал аналогичные вещи с Perl, двойной fork () и отсоединением от родительского процесса. Вся работа по получению http должна выполняться в разветвленном процессе.

0
ответ дан 24 November 2019 в 11:37
поделиться

PHP может быть или не быть лучшим инструментом, но вы знаете, как его использовать, а остальная часть вашего приложения написана с использованием Это. Эти два качества в сочетании с тем фактом, что PHP «достаточно хорош», делают довольно веские аргументы в пользу его использования вместо Perl, Ruby или Python.

Если ваша цель - выучить другой язык, выберите один и используйте его. Любой язык, который вы упомянули, сработает, без проблем. Мне нравится Perl, но то, что вам нравится, может быть другим.

Symcbean дает несколько полезных советов по управлению фоновыми процессами по его ссылке.

Короче говоря, напишите сценарий CLI PHP для обработки длинных битов. Убедитесь, что он каким-то образом сообщает о статусе. Создайте страницу php для обработки обновлений статуса, используя AJAX или традиционные методы. Ваш сценарий запуска запустит процесс, выполняющийся в его собственном сеансе, и вернет подтверждение того, что процесс выполняется.

Удачи.

3
ответ дан 24 November 2019 в 11:37
поделиться

Да. Если необходимо внести изменения в пробел, рекомендуется выполнить их в отдельной фиксации, содержащей только этот вид очистки. Это позволяет избежать проблем с попытками увидеть, какая часть гигантского различия является фактическими изменениями кода, и какая часть является просто форматированием (косметическими) изменениями.

Это означает, что вы должны попытаться свести эти изменения к минимуму и делать это только тогда, когда это необходимо и совместимо с любыми стандартами кодирования, используемыми в вашей компании/сообществе/проекте/и т.д.

-121--1740751-

foreach как разумный способ итерации через очередь , когда вы не удаляете элементы

Когда вы хотите удалить и обработать элементы, безопасный для потоков, правильный способ - просто удалить их по одному и обрабатывать их после удаления.

Одним из способов является

// the non-thread safe way
//
while (queueList.Count > 0)
{
    Order orderItem = queueList.Dequeue();
    Save(orderItem);
    Console.WriteLine("Id :{0} Name {1} ", orderItem.Id, orderItem.Name);
}

Количество элементов в очереди может изменяться между queureList.Count и queureList.Dequeue (), поэтому для обеспечения безопасности потока необходимо просто использовать Dequeue, но Dequeue будет выбрасываться, когда очередь пуста, поэтому необходимо использовать обработчик исключений.

// the thread safe way.
//
while (true)
{
    Order orderItem = NULL;
    try { orderItem = queueList.Dequeue(); } catch { break; }
    if (null != OrderItem)
    {
        Save(orderItem);
        Console.WriteLine("Id :{0} Name {1} ", orderItem.Id, orderItem.Name);
    }
}
-121--3338977-

Я согласен с ответами, которые говорят, что это должно быть выполнено в фоновом процессе. Но также важно, чтобы вы сообщали о состоянии, чтобы пользователь знал, что работа выполняется.

При получении запроса PHP на запуск процесса можно сохранить в базе данных представление задачи с уникальным идентификатором. Затем запустите процесс очистки экрана, передав ему уникальный идентификатор. Сообщите приложению iPhone, что задача была запущена и что для получения последнего статуса необходимо проверить указанный URL-адрес, содержащий новый идентификатор задачи. Приложение iPhone теперь может опрашивать (или даже "долго опрашивать") этот URL. Тем временем фоновый процесс обновит представление задачи в базе данных по мере ее работы с процентом завершения, текущим шагом или любыми другими индикаторами состояния, которые вы хотите. И когда он закончит, он установит завершенный флаг.

1
ответ дан 24 November 2019 в 11:37
поделиться

Нет, PHP - не лучшее решение.

Я не уверен насчет Ruby или Perl, но с Python вы можете переписать парсер страниц, сделав его многопоточным, и он, вероятно, будет работать как минимум в 20 раз быстрее. Написание многопоточных приложений может быть довольно сложной задачей, но самым первым приложением на Python, которое я написал, был многопоточный парсер страниц. И вы можете просто вызвать скрипт Python изнутри своей страницы PHP, используя одну из функций выполнения оболочки.

5
ответ дан 24 November 2019 в 11:37
поделиться
Другие вопросы по тегам:

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