2014-10-01 2 views
0

Я пытаюсь заставить PHP сказать Apache, чтобы закрыть соединение и, соответственно, освободить рабочий поток. Причина в том, что у меня есть сценарий, который вызывается с запросом клиента и занимает некоторое время для обработки, но ничего не возвращает клиенту, поэтому просто не имеет смысла держать занятый поток. Код настоящее время я использую:Как закрыть поток Apache из PHP?

ignore_user_abort(true); 
header('Content-Length: 0'); 
flush(); 
ob_end_flush(); 
header('Connection: Close'); 

Поскольку я посылаю дополнительный асинхронный запрос к этому скрипту из запроса исходного пользователя, Content-Length: 0 не будет портить ответ запроса клиента.

В любом случае, когда я иду следить за тем, что делает сервер, я вижу, что есть рабочий поток, занятый длительным запросом, который я точно не хочу. Я хочу, чтобы скрипт работал тихо назад, не занимая потоки Apache. Как я могу это сделать?

+0

На самом деле это не многопоточность. Вы можете многопоточно использовать 'pthreads' (не тривиально, как это обычно требует повторной компиляции PHP), и я слышал, что это можно сделать даже в рамках процесса Apache. Или используйте систему очередей, такую ​​как Gearman или Resque. – halfer

+0

Если вы используете общий хостинг, возможно, стоит попробовать ['pfork'] (http://uk3.php.net/manual/en/function.pcntl-fork.php) - здесь не так много вариантов кроме 'cron'. – halfer

ответ

2

Это звучит как плохая практика и множество неприятностей, например. с параллелизмом и балансировкой нагрузки.

Рассмотрим реализацию очереди задач:

  1. Ваш клиент хочет, чтобы добавить задачу в очередь по желанию.
  2. Клиент отправляет запрос Apache, в котором выполняется PHP-код.
  3. PHP анализирует ввод и создает задачу, которая добавляется в очередь.
  4. Сервер возвращает пустой ответ клиенту.

Затем настройте задание демона или cron, которое обрабатывает вышеупомянутую очередь в фоновом режиме, вне Apache.

Это дает вам прекрасный контроль над тем, что происходит, когда вам не нужны такие хаки. В качестве бонуса вы постоянно проверяете использование ресурсов, контролируя, как быстро обрабатывается очередь. (Особенно полезно, если вы разговариваете с внешним API, который ограничивает трафик.)

Если вы хотите, чтобы ваша очередь была параллельной, ничто не мешает вам - подумайте о настройке нескольких пулов задач, и каждая задача при создании будет назначена случайный пул задач. Затем настройте экземпляр демона для каждого пула задач - нет необходимости в потоках PHP или что-то в этом роде.

+0

Это имеет смысл, но я не вижу, как я могу добиться того, что я пытаюсь сделать с помощью очереди и cron. Что такое «длинный запрос» на самом деле является частным сервером сокета. Мне нужно, чтобы сервер был запущен, как только запрос отправляется и запускает cronjob каждую секунду, определенно, это не умная идея:? –

+0

В этом случае подход демона был бы лучше - пусть постоянный демон PHP знает, что вы хотите открыть сокет, и он открывает его. Трудная часть состоит в том, чтобы выяснить, как сделать interop right - мониторинг текстовых файлов не очень хорош. –

+0

Если одновременно нужно открывать несколько сокетов, вместо того чтобы пытаться сделать многопоточность постоянным демонами, вы можете просто отложить отдельные процессы PHP, используя команду типа 'exec()'. –