Есть ли в PHP потоковая обработка?


Я нашел этот пакет PECL под названием threads, но еще не выпущен. И на веб-сайте PHP ничего не появляется.

Author: Josh K, 2008-10-16

13 answers

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

 40
Author: Wilco, 2008-10-16 18:55:23

Из руководства по PHP для потоки добавочный номер:

Pthreads - это объектно-ориентированный API, который позволяет использовать многопоточность в PHP. Он включает в себя все инструменты, необходимые для создания многопоточных приложений, предназначенных для Интернета или консоли. PHP-приложения могут создавать, читать, записывать, выполнять и синхронизировать с потоками, рабочими и стекируемыми файлами.

Как бы невероятно это ни звучало, это чистая правда. Сегодня PHP может быть многопоточным для желающие попробовать.

Первый выпуск PHP4, 22 мая 2000 года, PHP был поставлен с потокобезопасной архитектурой - способом выполнения нескольких экземпляров интерпретатора в отдельных потоках в многопоточных средах SAPI (серверный API). В течение последних 13 лет дизайн этой архитектуры поддерживался и совершенствовался: с тех пор она используется в производстве на крупнейших веб-сайтах мира.

Потоковая передача в пользовательской среде никогда не была проблемой для команды PHP, и она остается таковой и сегодня. Вы должны понимать, что в мире, где PHP занимается своим бизнесом, уже существует определенный метод масштабирования - добавление оборудования. За многие годы существования PHP аппаратное обеспечение становилось все дешевле и дешевле, и поэтому это все меньше и меньше беспокоило команду PHP. В то время как он становился дешевле, он также стал намного мощнее; сегодня наши мобильные телефоны и планшеты имеют двух- и четырехъядерные архитектуры и много оперативной памяти, чтобы дополнить их, наши настольные компьютеры и серверы обычно у нас 8 или 16 ядер, 16 и 32 гигабайта оперативной памяти, хотя мы не всегда можем иметь два в рамках бюджета, и наличие двух настольных компьютеров редко бывает полезным для большинства из нас.

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

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

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

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

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

Pthreads использует потоки Posix (даже в Windows), то, что создает программист, является реальными потоками выполнения, но для того, чтобы эти потоки были полезными, они должны быть осведомлен о PHP - способен выполнять пользовательский код, обмениваться переменными и использовать полезные средства связи (синхронизация). Таким образом, каждый поток создается с экземпляром интерпретатора, но по замыслу его интерпретатор изолирован от всех других экземпляров интерпретатора - точно так же, как многопоточные серверные среды API. pthreads пытается преодолеть этот разрыв разумным и безопасным способом. Многие проблемы программиста потоков в C просто не существуют для программиста pthreads, по дизайн, pthreads - это копирование при чтении и копирование при записи (оперативная память дешевая), поэтому никакие два экземпляра никогда не манипулируют одними и теми же физическими данными, но они оба могут влиять на данные в другом потоке. Тот факт, что PHP может использовать потокобезопасные функции в своем основном программировании, совершенно не имеет значения, пользовательские потоки и операции полностью безопасны.

Зачем копировать при чтении и копировать при записи:

public function run() {
    ...
    (1) $this->data = $data;
    ...
    (2) $this->other = someOperation($this->data);
    ...
}

(3) echo preg_match($pattern, $replace, $thread->data);

(1) Пока в хранилище данных объектов pthreads удерживается блокировка чтения и записи, данные копируются из его исходного местоположения в памяти в хранилище объектов. pthreads не корректирует количество ссылок переменной, Zend может освободить исходные данные, если на них больше нет ссылок.

(2) Аргумент для некоторой операции ссылается на хранилище объектов, сохраненные исходные данные, которые сами по себе являются копией результата (1), снова копируются для механизма в контейнер zval, в то время как это происходит, блокировка чтения удерживается в хранилище объектов, блокировка снимается, и механизм может выполните эту функцию. Когда создается zval, он имеет значение 0, что позволяет механизму освободить копию по завершении операции, поскольку других ссылок на него не существует.

(3) Последний аргумент для preg_match ссылается на хранилище данных, получается блокировка чтения, набор данных в (1) копируется в zval, снова с количеством ссылок 0. Блокировка снята, вызов preg_match работает с копией данных, которая сама является копией исходных данных.

Вещи, чтобы знать:

  • Хэш-таблица хранилища объектов, в которой хранятся данные, потокобезопасная, является
    на основе таблицы TSHASH, поставляемой с PHP, от Zend.

  • Хранилище объектов имеет блокировку чтения и записи, для таблицы TSHASH предусмотрена дополнительная блокировка доступа, так что, если требуется (и это так, var_dump/print_r, прямой доступ к свойствам, поскольку движок PHP хочет ссылаться на них), pthreads может манипулировать таблицей TSHASH за пределами определенного API-интерфейс.

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

Это означает:

  • Когда происходит запись, удерживается не только блокировка чтения и записи, но и дополнительная блокировка доступа. Сама таблица заблокирована, нет никакого способа, которым другой контекст может заблокировать, прочитать, записать или повлиять на нее.

  • Когда происходит считывание, не только считывается блокировка удерживается, но дополнительная блокировка доступа тоже, снова стол заблокирован.

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

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

Большинство библиотек и расширений, доступных для PHP, являются тонкими оболочками для сторонних разработчиков, основная функциональность PHP в какой-то степени то же самое. pthreads - это не тонкая оболочка вокруг потоков Posix; это API для потоковой обработки, основанный на потоках Posix. Нет никакого смысла в реализация потоков в PHP, которые пользователи не понимают или не могут использовать. Нет никаких причин, по которым человек, не знающий, что такое мьютекс или что он делает, не должен иметь возможности использовать все, что у него есть, как с точки зрения навыков, так и ресурсов. Объект функционирует как объект, но везде, где в противном случае столкнулись бы два контекста, pthreads обеспечивает стабильность и безопасность.

Любой, кто работал на java, увидит сходство между объектом pthreads и потоковой обработкой в java, те же самые люди, без сомнения, видели ошибку под названием ConcurrentModificationException - поскольку это звучит как ошибка, вызванная средой выполнения java, если два потока одновременно записывают одни и те же физические данные. Я понимаю, почему он существует, но меня сбивает с толку то, что с такими дешевыми ресурсами, как они есть, в сочетании с тем фактом, что среда выполнения способна обнаруживать параллелизм в точное и единственное время, когда может быть достигнута безопасность для пользователя, что он решает выдать возможную фатальную ошибку во время выполнения, а не управляйте выполнением и доступом к данным.

Я полагаю, что pthreads не будет выдавать таких глупых ошибок, API написан для того, чтобы сделать потоковую обработку максимально стабильной и совместимой.

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

Наконец, из руководства по PHP:

Pthreads был и остается экспериментом с довольно хорошими результатами. Любое из его ограничений или функции могут измениться в любое время; такова природа экспериментов. Его ограничения, часто налагаемые реализацией, существуют по уважительной причине; цель pthreads - предоставить полезное решение для многозадачности в PHP на любом уровне. В среде, в которой выполняется pthreads, необходимы некоторые ограничения и ограничения для обеспечения стабильной среды.

 172
Author: Joe Watkins, 2013-01-28 11:44:57

Вот пример того, что предложил Уилко:

$cmd = 'nohup nice -n 10 /usr/bin/php -c /path/to/php.ini -f /path/to/php/file.php action=generate var1_id=23 var2_id=35 gen_id=535 > /path/to/log/file.log & echo $!';
$pid = shell_exec($cmd);

В основном это выполняет PHP-скрипт в командной строке, но сразу возвращает PID, а затем запускается в фоновом режиме. (Эхо$! гарантирует, что больше ничего не будет возвращено, кроме PID.) Это позволяет вашему PHP-скрипту продолжить или завершить работу, если вы хотите. Когда я использовал это, я перенаправил пользователя на другую страницу, где каждые 5-60 секунд выполняется вызов AJAX, чтобы проверить, работает ли отчет. (У меня есть таблица для хранения gen_id и пользователя, с которым он связан.) Сценарий проверки выполняет следующее:

exec('ps ' . $pid , $processState);
if (count($processState) < 2) {
     // less than 2 rows in the ps, therefore report is complete
}

Здесь есть короткий пост об этой технике: http://nsaunders.wordpress.com/2007/01/12/running-a-background-process-in-php/

 48
Author: Darryl Hein, 2013-01-17 01:50:10

Короче говоря: да, в php есть многопоточность, но вместо этого вы должны использовать многопроцессорную обработку.

Информация о бэкграуде: потоки и процессы

Всегда существует некоторая путаница в различии потоков и процессов, поэтому я кратко опишу оба:

  • Поток - это последовательность команд, которые будет обрабатывать центральный процессор. Единственные данные, из которых он состоит, - это счетчик программ. Каждое ядро процессора будет обрабатывать только один поток за раз, но может переключаться между выполнение различных из них с помощью планирования.
  • Процесс представляет собой набор общих ресурсов. Это означает, что он состоит из части памяти, переменных, экземпляров объектов, дескрипторов файлов, мьютексов, подключений к базе данных и так далее. Каждый процесс также содержит один или несколько потоков. Все потоки одного и того же процесса совместно используют его ресурсы, поэтому вы можете использовать переменную в одном потоке, созданную в другом. Если эти потоки являются частями двух разных процессов, то они не могут получить доступ друг к другу ресурсы напрямую. В этом случае вам нужна межпроцессная связь, например, через каналы, файлы, сокеты...

Многопроцессорная обработка

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

В php у вас есть два способа создать новый процесс:

Позвольте ОС сделать это за вас: вы можете указать своей операционной системе создать новый процесс и запустить в нем новый (или тот же) php-скрипт.

  • Для linux вы можете использовать следующее или рассмотрим ответ Дэррила Хейна:

    $cmd = 'nice php script.php 2>&1 & echo $!';
    pclose(popen($cmd, 'r'));
    
  • Для windows вы можете использовать следующее:

    $cmd = 'start "processname" /MIN /belownormal cmd /c "script.php 2>&1"';
    pclose(popen($cmd, 'r'));
    

Сделайте это самостоятельно с помощью вилки: php также предоставляет возможность использовать разветвление через функцию pcntl_fork(). Хороший учебник о том, как это сделать, можно найти здесь, но я настоятельно рекомендую не использовать его, так как вилка является преступлением против человечества и особенно против ООП.

Многопоточность

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

Стандартный php не обеспечивает многопоточность, но есть (экспериментальное) расширение, которое на самом деле это делает - pthreads. Его документация по api даже превратил его в php.net . С его помощью вы можете делать некоторые вещи, как вы можете в реальных языках программирования:-) вот так:

class MyThread extends Thread {
    public function run(){
        //do something time consuming
    }
}

$t = new MyThread();
if($t->start()){
    while($t->isRunning()){
        echo ".";
        usleep(100);
    }
    $t->join();
}

Для linux есть руководство по установке прямо здесь, в stackoverflow.

Для windows теперь есть один:

  • Сначала вам нужна потокобезопасная версия php.
  • Вам нужны предварительно скомпилированные версии как pthreads, так и его php-расширения. Их можно скачать здесь. Сделай убедитесь, что вы скачали версию, совместимую с вашей версией php.
  • Копия php_pthreads.dll (из zip-файла, который вы только что загрузили) в папку расширения php ([phpdirectory]/ext).
  • Копия pthreadVC2.dll в [каталог PHP] (корневая папка, а не папка расширения).
  • Отредактируйте [Каталог PHP]/php.ini и вставьте следующую строку

    extension=php_pthreads.dll
    
  • Проверьте это с помощью приведенного выше сценария с некоторым сном или чем-то еще прямо там, где комментарий является.

А теперь большое НО: Хотя это действительно работает, php изначально не был создан для многопоточности. Существует потокобезопасная версия php, и начиная с версии 5.4 она, похоже, почти не содержит ошибок, но использование php в многопоточной среде по-прежнему не рекомендуется в руководстве по php (но, возможно, они просто еще не обновили свое руководство по этому вопросу). Гораздо большая проблема может заключаться в том, что многие распространенные расширения не являются потокобезопасными . Так что вы можете получить потоки с этим расширением php, но функции, от которых вы зависите, все еще не являются потокобезопасными, поэтому вы, вероятно, столкнетесь с условиями гонки, тупиками и т. Д. В коде, который вы не писали сами...

 24
Author: Francois Bourgeois, 2017-05-23 12:26:22

Вы можете использовать pcntl_fork() для достижения чего-то похожего на потоки. Технически это отдельные процессы, поэтому связь между ними не так проста с потоками, и я считаю, что это не сработает, если PHP вызывается apache.

 17
Author: davr, 2008-10-16 22:30:26

Если кому-то интересно, я возродил php_threading (не то же самое, что потоки, но похоже), и у меня действительно есть это до такой степени, что оно работает (несколько) хорошо!

Страница проекта

Скачать (для Windows PHP 5.3 VC9 TS)

Примеры

ПРОЧТИТЕ МЕНЯ

 13
Author: Alec Gorge, 2012-09-12 21:20:39

pcntl_fork() это то, что вы ищете, но его процесс разветвляется, а не пронизывает. таким образом, у вас возникнет проблема обмена данными. для их решения вы можете использовать функции семафора phps (http://www.php.net/manual/de/ref.sem.php ) очереди сообщений могут быть немного проще для начала, чем сегменты общей памяти.

В любом случае, стратегия, которую я использую в разрабатываемой мной веб-платформе, которая загружает ресурсоемкие блоки веб-страницы (возможно, с внешними запросами) параллель: я делаю очередь заданий, чтобы узнать, какие данные я жду, а затем я отказываюсь от заданий для каждого процесса. после этого они хранят свои данные в кэше apc под уникальным ключом, к которому может получить доступ родительский процесс. как только все данные будут там, это продолжится. я использую simple usleep() для ожидания, потому что межпроцессное взаимодействие в apache невозможно (дети потеряют связь со своими родителями и станут зомби...). итак, это подводит меня к последнему вопросу: важно самостоятельно убивать каждого дитя! есть также классы, которые разветвляют процессы, но сохраняют данные, я их не изучал, но у zend framework есть один, и они обычно выполняют медленный, но надежный код. вы можете найти его здесь: http://zendframework.com/manual/1.9/en/zendx.console.process.unix.overview.html я думаю, что они используют сегменты shm! ну и последнее, но не менее важное: на этом веб-сайте zend есть ошибка, незначительная ошибка в примере.

while ($process1->isRunning() && $process2->isRunning()) {
    sleep(1);
}
should of course be:
while ($process1->isRunning() || $process2->isRunning()) {
    sleep(1);
}
 7
Author: The Surrican, 2011-11-03 12:27:57

На основе PThreads активно разрабатывается расширение для потоков, которое выглядит очень многообещающим в https://github.com/krakjoe/pthreads

 6
Author: JasonDavis, 2012-10-24 04:38:17

Просто обновление, похоже, что PHP-ребята работают над поддержкой потока и теперь он доступен.

Вот ссылка на него: http://php.net/manual/en/book.pthreads.php

 6
Author: happyhardik, 2013-09-14 15:28:27

У меня есть класс потоковой обработки PHP, который безупречно работает в производственной среде уже более двух лет.

РЕДАКТИРОВАТЬ: Теперь это доступно как библиотека композитора и как часть моей платформы MVC, Hazaar MVC.

См.: https://git.hazaarlabs.com/hazaar/hazaar-thread

 5
Author: Jamie Carl, 2016-09-01 00:04:01

Я знаю, что это очень старый вопрос, но вы могли бы взглянуть на http://phpthreadlib.sourceforge.net/

Двунаправленная связь, поддержка Win32 и никаких расширений не требуется.

 2
Author: Unsigned, 2011-02-23 15:44:14

Когда-нибудь слышали о appserver от techdivision?

Он написан на php и работает как сервер приложений, управляющий многопоточностью для php-приложений с высоким трафиком. Все еще находится в бета-версии, но очень многообещающий.

 1
Author: user2627170, 2013-07-28 08:48:12

Существует довольно неясная и скоро устаревшая функция под названием галочки. Единственное, для чего я когда-либо его использовал, - это разрешить сценарию захватывать SIGKILL (Ctrl+C) и изящно закрываться.

 -3
Author: troelskn, 2008-10-19 12:19:48