Skip to content

Latest commit

 

History

History
144 lines (102 loc) · 8.6 KB

1.Main.md

File metadata and controls

144 lines (102 loc) · 8.6 KB

Основная информация


  1. Базовая информация о потоке
  2. Упрощенное создание потока с замыканиями
  3. Базовая информация о пуле потоков

1 - Базовая информация о потоке

"Поток" представляет из себя наследника класса 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();

2 - Упрощенное создание потока с замыканиями

Вы можете еще проще создавать потоки - из замыканий, с помощью класса SimpleThread. Такие потоки, по умолчанию, не ответвляют сразу дочерний процесс и не многозадачны (дочерний процесс умирает после каждой задачи). Это может быть изменено с помощью второго аргумента в SimpleThread::create.

Аргументы в потоках-замыканиях всегда можно получать как в обычной функции.

$result = SimpleThread::create(function($arg) {
	return $arg;
})->run(123)->wait()->getResult();

Начиная с PHP 5.4.0 внутри замыкания можно использовать все стандартные методы потока через $this, как и в обычном классе-потоке (больше информации).

3 - Базовая информация о пуле потоков

Пул потоков можно создать с помощью класса 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();

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