В PHP есть потоки? - PullRequest
       48

В PHP есть потоки?

125 голосов
/ 16 октября 2008

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

Ответы [ 13 ]

175 голосов
/ 27 января 2013

Из руководства по PHP для pthreads расширение:

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

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

Первый выпуск PHP4, 22 мая 2000 г., PHP был поставлен с поточно-ориентированной архитектурой - способом для выполнения нескольких экземпляров своего интерпретатора в отдельных потоках в многопоточных средах SAPI (Server 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 не корректирует refcount переменной, Zend может освободить исходные данные, если на них больше нет ссылок.

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

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

Что нужно знать:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

48 голосов
/ 17 октября 2008

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

$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, а затем запускается в фоновом режиме. (Echo $! Гарантирует, что больше ничего не будет возвращено, кроме 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/

40 голосов
/ 16 октября 2008

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

24 голосов
/ 07 января 2013

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

Справочная информация: потоки и процессы

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

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

Multiprocessing

Вы можете добиться параллельных вычислений, создавая новые процессы (которые также содержат новый поток) с помощью 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 () . Хороший учебник о том, как это сделать, можно найти здесь , но я настоятельно рекомендую его не использовать, поскольку 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's.

Для Windows теперь есть одна:

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

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

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

17 голосов
/ 17 октября 2008

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

13 голосов
/ 25 августа 2010

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

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

Загрузить (для Windows PHP 5.3 VC9 TS)

Примеры

README

7 голосов
/ 08 августа 2010

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

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

while ($process1->isRunning() && $process2->isRunning()) {
    sleep(1);
}
should of course be:
while ($process1->isRunning() || $process2->isRunning()) {
    sleep(1);
}
6 голосов
/ 29 декабря 2012

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

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

6 голосов
/ 24 октября 2012

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

5 голосов
/ 08 февраля 2011

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...