- Базовая информация о потоке
- Упрощенное создание потока с замыканиями
- Базовая информация о пуле потоков
"Поток" представляет из себя наследника класса Thread
. Он разветвляет (форкает) процесс-родитель и позволяет выполнять различные вычисления параллельно в двух процессах. Связь между процессами поддерживается с помощью пары сокетов, используя эффективную модель "event loop".
Поток также может работать в режиме совместимости - без реальной параллельности, форков и "event loop". На случай если нет каких либо зависимостей или для тестирования. Для принудительного включения этого режима установите свойство Thread::$useForks
в false
.
Для работы вам нужно переопределить метод process
- код в нем, как раз и будет вызываться асинхронно.
class ExampleThread extends Thread
{
function process()
{
// Код, выполняемый асинхронно
}
}
Аргументы для задачи можно получать с помощью методов getParam
, getParams
. Передаются аргументы как в обычную функцию при вызове метода run
. С помощью опции $argumentsMapping
можно включить получение аргументов, как в обычной функции, но это немного замедляет работу и поэтому отключено по умолчанию.
class ExampleThread extends Thread
{
function process()
{
// Первый параметр
echo $this->getParam(0); // 12
// Второй параметр
echo $this->getParam(1); // 79
// Массив со всеми параметрами
$params = $this->getParams();
}
}
$thread = new ExampleThread();
$thread->wait()->run(12, 79);
Результаты выполнения задачи могут быть отправлены с помощью обычного return
и получены с помощью метода getResult
:
class ExampleThread extends Thread
{
function process()
{
return 123;
}
}
$thread = new ExampleThread();
echo $thread->wait()->run()->wait()->getResult(); // 123
Метод wait
используется для синхронизации в дочернем и родительском процессе - он запускает "event loop", в котором происходит передача информации из родительского процесса в дочерний и обратно.
После создания инстанса "потока" перед запуском задачи нужно один раз вызывать метод wait
, чтобы дождаться инициализации потока. Можно отключить такое поведение с помощью включения опции $preforkWait
ожидание будет происходить автоматически и вызывать метод wait
перед первым вызовом метода run
будет не нужно. Но эффективнее этого не делать.
Подробнее про варианты настройки потока можно прочитать в соответствующей части документации.
Метод getSuccess
позволяет узнать, успешно или нет закончилось последнее выполнение задачи. Если задача не выполнена, то можно узнать код ошибки с помощью getLastErrorCode()
и текст ошибки с помощью getLastErrorMsg()
.
После работы настоятельно рекоммендуется явно освободить все ресурсы, чтобы избежать различных утечек:
$thread->cleanup();
Вы можете еще проще создавать потоки - из замыканий, с помощью класса SimpleThread
. Такие потоки, по умолчанию, не ответвляют сразу дочерний процесс и не многозадачны (дочерний процесс умирает после каждой задачи). Это может быть изменено с помощью второго аргумента в SimpleThread::create
.
Аргументы в потоках-замыканиях всегда можно получать как в обычной функции.
$result = SimpleThread::create(function($arg) {
return $arg;
})->run(123)->wait()->getResult();
Начиная с PHP 5.4.0 внутри замыкания можно использовать все стандартные методы потока через $this
, как и в обычном классе-потоке (больше информации).
Пул потоков можно создать с помощью класса ThreadPool
.
$pool = new ThreadPool(
'ExampleThread', // Полное имя класса потока
8 // Число потоков
);
Пул позволяет эффективно и удобно распределять задачи между несколькими потоками, получать результаты выполнения, события из потоков и.т.п. В общем случае эффективно использовать число потоков по числу ядер процессора, но для достижения большей эффективности можно подобрать число уже на конкретной системе экспериментально.
Для основной работы с пулом используются три метода: hasWaiting
, run
, wait
.
while ($pool->hasWaiting()) {
$threadId = $pool->run();
// ...
}
if ($results = $pool->wait($failed)) {
foreach ($results as $threadId => $result) {
// ...
}
}
if ($failed) {
foreach ($failed as $threadId => $err) {
list($errorCode, $errorMessage) = $err;
// ...
}
}
hasWaiting
сообщает есть ли в пуле свободные потоки. Если есть, то в свободном потоке можно запустить задачу с помощью метода run
. Он принимает аргументы для задачи и возвращает ID потока, который начал задачу выполнять.
Результаты выполнения можно получить с помощью метода wait
. Он запускает "event loop", ожидая результатов и возвращает массив успешных результатов. Массив ошибок при выполнении задач можно получить по ссылке через первый аргумент метода wait
. Каждая ошибка включает код ошибки и поясняющий текст.
Идентифицировать успешные и неудачные результаты можно с помощью ID потока.
После работы настоятельно рекоммендуется явно освободить все ресурсы, чтобы избежать различных утечек:
$pool->cleanup();
Полный пример использования пула с обработкой ошибок можно посмотреть среди остальных примеров.