Параллельная обработка в PHP - как вы это делаете?

В настоящее время я пытаюсь реализовать очередь заданий на php. Затем очередь будет обработана как пакетное задание и должна иметь возможность обрабатывать некоторые задания параллельно.

Я уже провел небольшое исследование и нашел несколько способов его реализации, но я не очень хорошо осведомлен об их преимуществах и недостатках.

Например. выполнение параллельной обработки путем вызова сценария несколько раз через fsockopen, как описано здесь:
Простая параллельная обработка в PHP

Другой способ, который я нашел, - это использование curl_multi функций.
curl_multi_exec Документы PHP

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

Я также читал о pcntl_fork, который, кажется, тоже помогает справиться с проблемой. Но похоже, что это может стать действительно беспорядочным, если вы действительно не знаете, что делаете (как я в данный момент).

Я также посмотрел на Gearman, но там мне также нужно было бы динамически создавать рабочие потоки по мере необходимости, а не просто запускать несколько и позволять серверу заданий gearman затем отправлять их бесплатным рабочим. Тем более, что потоки должны завершаться без ошибок после выполнения одного задания, чтобы не столкнуться с возможными утечками памяти (код в этой проблеме может быть несовершенным).
Начало работы с Gearman

Итак, мой вопрос: как вы справляетесь с параллельной обработкой в ​​PHP? И почему вы выбираете свой метод, какие преимущества / недостатки могут иметь разные методы?


person enricog    schedule 24.05.2011    source источник
comment
Принял ответ Квамиса, потому что я собираюсь сделать это сейчас именно так. Другие ответы также хороши и могут также взглянуть на их подходы в будущем. Спасибо еще раз.   -  person enricog    schedule 25.05.2011
comment
Для подробного обсуждения различных подходов см. stackoverflow.com/ вопросы / 209774 / does-php-have-threading /   -  person Francois Bourgeois    schedule 08.01.2013


Ответы (9)


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

Мне не нравится fsockopen(), потому что он откроет соединение с сервером, которое будет расти и может достигнуть лимита соединения apache

Мне не нравятся curl функции по той же причине

Мне не нравится pnctl, потому что ему нужно доступное расширение pnctl, и вам нужно отслеживать отношения родитель / потомок.

никогда не играл с редуктором ...

person Quamis    schedule 24.05.2011
comment
Но как бы выглядел ваш менеджер потоков? Основная проблема, с которой я столкнулся, заключается в том, как лучше всего создать эти потоки, а также позволить им аккуратно выйти после того, как они завершат свою работу. И exec блокируется до тех пор, пока команда не будет завершена, поэтому я не могу запускать задания параллельно или я здесь ошибаюсь? - person enricog; 24.05.2011
comment
вы можете запускать вещи в фоновом режиме :) stackoverflow.com/questions / 45953 / - person Quamis; 24.05.2011
comment
Ах конечно ... Спасибо, особо не думал об этом :) На самом деле уже есть пример кода в комментариях к руководству по exec php, где также легко показано, как тогда отслеживать процессы. - person enricog; 24.05.2011
comment
нужно помнить, что некоторые серверы не разрешают exec () по соображениям безопасности - person Grzegorz; 15.04.2013
comment
@Gacek: это на самом деле специфичная для PHP конфигурация, а не специфичная для сервера. Если у вас нет доступа к конфигурации сервера, в любом случае будет сложно выполнить параллельную обработку. - person Quamis; 17.04.2013

Думаю, у нас есть 3 варианта:

А. Многопоточность:

PHP изначально не поддерживает многопоточность. Но есть одно расширение PHP (экспериментальное) под названием pthreads (https://github.com/krakjoe/pthreads ), который позволяет вам это делать.

Б. Многопроцессорность:

Это можно сделать 3 способами:

  • Разветвление
  • Выполнение команд
  • Трубопровод

С. Распределенная параллельная обработка:

Как это работает:

  1. Приложение Client отправляет данные (сообщение AKA), «могут быть отформатированы в формате JSON», в движок (MQ Engine), «может быть локальным или внешним веб-сервисом»
  2. MQ Engine хранит данные «в основном в памяти и, возможно, в базе данных» внутри очередей (вы можете определить имя очереди)
  3. Приложение Client запрашивает у MQ Engine данные (сообщение) для их обработки в порядке (FIFO или в зависимости от приоритета) «вы также можете запросить данные из определенной очереди».


Некоторые движки MQ:

  • ZeroMQ (хороший вариант, сложный в использовании) библиотека IPC, ориентированная на сообщения, представляет собой сервер очереди сообщений в Erlang, хранит задания в памяти. Это библиотека сокетов, которая действует как среда параллелизма. Быстрее TCP для кластерных продуктов и суперкомпьютеров.
  • RabbitMQ (хороший вариант, простой в использовании), самостоятельный хостинг, корпоративные очереди сообщений. На самом деле это не рабочая очередь, а скорее очередь сообщений, которая может использоваться как рабочая очередь, но требует дополнительной семантики.
  • Beanstalkd (лучший вариант, простой в использовании) (встроенная поддержка Laravel, созданная facebook, для рабочей очереди) - имеет очень приятный инструмент "Консоль Beanstalkd".
  • Gearman (проблема: централизованная брокерская система для распределенной обработки)
  • Apache ActiveMQ - самый популярный брокер сообщений с открытым исходным кодом на Java (проблема: много ошибок и проблем)
  • Amazon SQS (встроенная поддержка Laravel, размещенная - поэтому администрирование не требуется. На самом деле это не рабочая очередь, поэтому потребуется дополнительная работа для обработки семантики, такой как скрытие задания)
  • IronMQ (встроенная поддержка Laravel, написана на языке Go, доступна как в облачной версии, так и локально)
  • Redis (Laravel имеет встроенную поддержку, но не так быстро, как не предназначена для этого)
  • Sparrow (написано на Ruby, основанном на кэше памяти)
  • Starling (написано на Ruby на основе memcache, встроено в twitter)
  • Пустельга (еще один QM)
  • Kafka (написано в LinkedIn на Scala)
  • EagleMQ, высокопроизводительный и легкий диспетчер очередей с открытым исходным кодом (написан на C)

Другие из них можно найти здесь: http://queues.io

person Mahmoud Zalt    schedule 06.04.2016
comment
Проект pthreads остановлен и не компилируется на php 7.4.x github.com/krakjoe/pthreads/issues/929 - person Meloman; 19.11.2020
comment
php 8 теперь поддерживает многопоточность. php.net/parallel - person Think Big; 15.04.2021
comment
не только php 8, но и php 7.2+ также поддерживает parallel - person T.Todua; 24.04.2021

Если ваше приложение будет работать в среде unix / linux, я бы посоветовал вам использовать вариант разветвления. Это в основном детская игра, чтобы заставить его работать. Я использовал его для менеджера Cron, и у меня был код для возврата к дружественному для Windows кодовому пути, если разветвление не было вариантом.

Варианты многократного выполнения всего сценария, как вы утверждаете, добавляют довольно много накладных расходов. Если ваш сценарий небольшой, это не проблема. Но вы, вероятно, привыкнете к параллельной обработке в PHP по своему выбору. И в следующий раз, когда у вас будет работа, которая использует 200 МБ данных, это вполне может стать проблемой. Так что вам лучше изучить способ, которым вы сможете придерживаться.

Я также протестировал Gearman, и он мне очень нравится. Есть несколько вещей, о которых стоит подумать, но в целом он предлагает очень хороший способ распространения работ на разные серверы, на которых работают разные приложения, написанные на разных языках. Помимо его настройки, его фактическое использование из PHP или любого другого языка, если на то пошло, это ... еще раз ... детская игра.

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

person inquam    schedule 24.05.2011

Вот краткое изложение нескольких вариантов параллельной обработки в PHP.

AMP

Оформить заказ Amp - простой асинхронный параллелизм - это, по-видимому, самая зрелая библиотека PHP. Смотрел на параллельную обработку.

Класс процесса Пеека

Этот класс был размещен в комментариях к функции PHP exec () и обеспечивает действительно простую отправную точку для создания новых процессов и отслеживания их.

Пример:

// You may use status(), start(), and stop(). notice that start() method gets called automatically one time.
$process = new Process('ls -al');

// or if you got the pid, however here only the status() metod will work.
$process = new Process();
$process.setPid(my_pid);

// Then you can start/stop/check status of the job.
$process.stop();
$process.start();
if ($process.status()) {
    echo "The process is currently running";
} else {
    echo "The process is not running.";
}

Другие сравниваемые варианты

Также есть отличная статья Асинхронная обработка или многозадачность в PHP , в котором объясняются плюсы и минусы различных подходов:

Швейцар

Кроме того, есть это простое руководство, которое было заключено в небольшой библиотека под названием Doorman.

Надеюсь, эти ссылки станут полезной отправной точкой для дальнейших исследований.

person Simon East    schedule 08.05.2018

Прежде всего, этот ответ основан на env ОС Linux. Еще одно расширение pecl является параллельным, вы можете установить его, выполнив pecl install parallel ,, но оно имеет некоторые предварительные требования :

  1. Установка ZTS (безопасность потоков Zend) Сборка версии PHP 7.2+
  2. если вы создаете это расширение по источнику, вы должны проверить файл конфигурации php.ini как файл конфигурации, а затем добавить к нему extension=parallel.so

затем просмотрите полную суть примера: https://gist.github.com/krakjoe/0ee02b887288720da9b7 или URL-адрес официального сайта php: https://www.php.net/manual/en/book.parallel.php

person kevin Sue    schedule 06.11.2019
comment
Простое руководство: harry.plus / blog / install-php-7-4-zts-with-ext-parallel-in-ubuntu - person ZalemCitizen; 30.06.2020

Я предпочитаю exec () и gearman. exec () прост, не требует подключения и потребляет меньше памяти. Gearman должен быть подключен к сокету, а рабочий должен занять некоторую память. Но gearman более гибкий и быстрый, чем exec (). И самое главное, он может развернуть воркера на другом сервере. Если работа требует много времени и ресурсов. Я использую gearman в своем текущем проекте.

person Magic    schedule 24.05.2011

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

Я считаю, что до тех пор, пока вы идеально его кодируете и следите за тем, чтобы поток был идеальным, вы должны помнить о ПАРАЛЛЕЛЬНОМ ПРОЦЕССЕ при реализации.

Где можно было ошибиться:

  1. Циклы - должны иметь возможность обрабатывать GLOBAL vars.
  2. Обработка некоторого набора транзакций - опять же, если вы правильно определите наборы, вы сможете это сделать.

Взгляните на этот пример - https://github.com/rakesh-sankar/Tools/blob/master/PHP/fork-parallel-process.php.

Надеюсь, это поможет.

person Rakesh Sankar    schedule 24.05.2011

Метод, описанный в разделе «Простая параллельная обработка в PHP», просто пугает - принцип в порядке - но реализация ??? Как вы уже отметили, curl_multi_ fns предоставляет гораздо лучший способ реализации этого подхода.

Но я думаю, что эти два способа значительно увеличат накладные расходы.

Да, вам, вероятно, не понадобится HTTP-стек клиента и сервера для передачи работы - но если вы не работаете в Google, время разработки намного дороже, чем затраты на оборудование - и существует множество инструментов для управления HTTP. / анализ производительности - и существует определенный стандарт, охватывающий такие вещи, как уведомления о состоянии и аутентификация.

Во многом то, как вы реализуете решение, зависит от требуемого уровня целостности транзакций и от того, нужна ли вам обработка по порядку.

Из упомянутых вами подходов я бы рекомендовал сосредоточиться на методе HTTP-запроса с использованием curl_multi_. Но если вам нужен хороший транзакционный контроль / для доставки заказа, вам обязательно нужно запустить демон брокера между источником сообщений и агентами обработки (есть хорошо написанный однопоточный сервер, подходящий для использования в качестве основы для брокера здесь). Обратите внимание, что агенты обработки должны обрабатывать по одному сообщению за раз.

Если вам нужно хорошо масштабируемое решение, обратите внимание на подходящую систему очередей сообщений, такую ​​как RabbitMQ.

HTH

C.

person symcbean    schedule 24.05.2011

Используйте собственный PHP (7.2+) Parallel, то есть:

use \parallel\Runtime;

$sampleFunc = function($num, $param2, $param3) { 
    echo "[Start: $num]";  
    sleep(rand(1,3) ); 
    echo "[end:$num]";   
};

for($i = 0; $i < 11; $i++) { 
    \parallel\run($sampleFunc,  [$param1=$i, $param2=null, $param3="blabla"] );
}
for ($i = 0; $i < 11; $i++) {
    echo " <REGULAR_CODE> ";
    sleep(1);
}

(Кстати, вам нужно будет пройти жесткий путь, чтобы установить PHP с поддержкой ZTS, а затем включить параллельный интерфейс. Я рекомендую phpbrew для этого.)

person T.Todua    schedule 24.04.2021