Web

Есть ли в PHP потоки

Я нашел пакет PECL под названием thread, для управления потоками в PHP. Как правильно управлять потоками в PHP?

 

Ответ 1

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

 

Ответ 2

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

pthreads - это объектно-ориентированный API, обеспечивающий многопоточность в PHP. Он включает все инструменты, необходимые для создания многопоточных приложений, предназначенных для Web или консоли. 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-приложения. 

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

pthreads использует Posix Threads (даже в Windows), программист создает реальные потоки выполнения, но чтобы эти потоки были полезны, они должны знать PHP уметь выполнять пользовательский код, разделять переменные и обеспечивать полезные средства связи (синхронизацию). Таким образом, каждый поток создается с экземпляром интерпретатора, но по замыслу интерпретатор изолирован от всех других экземпляров точно так же, как и многопоточные среды Server 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) Аргумент someOperation ссылается на хранилище объектов, исходные данные, которые сами по себе являются копией результата (1), снова копируются для движка в контейнер zval. Пока это происходит, блокировка чтения удерживается на хранилище объектов, блокировка снимается, и движок может выполнить функцию. Когда zval создается, его refcount равен 0, что позволяет движку освободить копию по завершении операции, поскольку других ссылок на него не существует.

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

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

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

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

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

 

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

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

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

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

Это архитектура shared nothing, и единственный способ существования – сосуществование. Те, кто немного подкован, увидят, что здесь происходит много копирования, и зададутся вопросом, хорошо ли это. Довольно много копирования происходит в динамическом времени выполнения, такова динамика этого языка. 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, некоторые ограничения и лимиты необходимы для того, чтобы обеспечить стабильную среду выполнения.

 

Ответ 3

Да, в php есть многопоточность, но вместо нее следует использовать многопроцессорность.

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

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

 

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

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

Многопроцессорные вычисления

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

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

  1. Для linux вы можете использовать следующее:

$cmd = 'nice php script.php 2>&1 & echo $!';

pclose(popen($cmd, 'r'));

  1. Для 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(){

        // сделать что-то трудоемкое

    }

}

 

$t = new MyThread();

if($t->start()){

    while($t->isRunning()){

        echo ".";

        usleep(100);

    }

    $t->join();

}

Для windows уже есть такая версия:

  1. Сначала вам нужна потокобезопасная версия php.

  2. Вам нужны предварительно скомпилированные версии как pthreads, так и его расширения php. Убедитесь, что вы скачали версию, совместимую с вашей версией php.

  3. Скопируйте php_pthreads.dll (из zip-архива) в папку расширения php ([phpDirectory]/ext).

  4. Скопируйте pthreadVC2.dll в [phpDirectory] (корневую папку - не папку расширений).

  5. Отредактируйте [phpDirectory]/php.ini и вставьте следующую строку

extension=php_pthreads.dll

  1. Протестируйте его с помощью скрипта выше с некоторым sleep или чем-то еще прямо там, где комментарий.

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

 

Схожие статьи

Песочницы HTML, CSS и для JS-кода: что это и для чего нужны
Web

Песочницы HTML, CSS и для JS-кода: что это и для чего нужны

Web

Проблемы при использовании $_REQUEST[]

Web

Как и где устанавливается $ _SERVER ['APP_DEBUG'] в Symfony >= 5.1?

Web

Как проверить, что все скобки правильно открыты/закрыты