возможно ли создать некоторый php-класс, который может запускать функции асинхронно? Вот что я сделал до сих пор:
class Worker extends Thread { protected $asyncFun; protected $paramsArray; public function run() { $asyncFun(/*parameters go here*/) } public function setAsyncFunction($func, $paramsArr) { $this->asyncFun = $func; $this->paramsArray = $paramsArr; } }
Вот как я хочу это назвать:
$worker = new Worker(); $worker->setAsyncFunction(foo, ["a", "b"]); $worker::start();
Последние версии pthreads поддерживают закрытие как членов, делая код очень простым:
<?php class Background extends Thread { public function __construct(callable $call, array $args = []) { $this->call = $call; $this->args = $args; } public function run() { call_user_func_array($this->call, $this->args); } protected $call; protected $args; } $background = new Background(function($greeting){ printf("%s\n", $greeting); }, ["Hello World"]); $background->start(); $background->join(); function named($greeting) { printf("%s\n", $greeting); } $background = new Background("named", ["Goodbye World"]); $background->start(); $background->join(); ?>
Тем не менее, это ужасно, трудно представить какую-либо функцию, которая так голодна, что для нее требуется собственный поток.
Вы начали по правильному пути с мыслью, что вы должны повторно использовать контекст и создать рабочий поток, pthreads имеет все это встроенное.
Более разумный код с использованием встроенных классов больше похож:
<?php class Background extends Threaded { public function __construct(callable $call, array $args = []) { $this->call = $call; $this->args = $args; } public function run() { call_user_func_array($this->call, $this->args); } protected $call; protected $args; } $pool = new Pool(4); $pool->submit(new Background(function($greeting){ printf("%s\n", $greeting); }, ["Hello World"])); $pool->shutdown(); ?>
Но это все еще не касается возвращаемого значения. Я предполагаю, что вы хотите получить результат вызовов, сделанных с помощью Pool
, в этом случае код выглядит больше:
<?php class Background extends Threaded { public function __construct(callable $call, array $args = []) { $this->call = $call; $this->args = $args; } public function run() { $this->synchronized(function(){ $this->result = call_user_func_array ($this->call, $this->args); $this->notify(); }); } public function getResult() { return $this->synchronized(function(){ while (!isset($this->result)) $this->wait(); return $this->result; }); } protected $call; protected $args; protected $result; } $pool = new Pool(4); $call = new Background(function($greeting){ return sprintf("%s\n", $greeting); }, ["Hello World"]); $pool->submit($call); echo $call->getResult(); $pool->shutdown(); ?>
Как вы можете видеть, вызов Background::getResult
приведет к появлению контекста вызова, ожидающего до получения результата, это может быть или не быть желательным, но подходит для хорошего примера.
PHP – синхронный язык. Почти все, что вы сделаете, заставит PHP зависать, пока он заканчивается, и который включает вызовы exec
если вы хотите получить ответ.
Реализация с использованием основных элементов PHP, вероятно, потребует от вас выполнения вызова exec
или cURL, а затем последующего просмотра вашего сервера для вывода позже в вашем скрипте.
Вы можете использовать PECL, о котором упоминал Дагон (Gearman), но я лично считаю, что использование менеджера очередей, такого как beanstalkd, намного проще в управлении.
Вот сайт для beanstalkd. И вот хорошая библиотека PHP для beanstalkd (с некоторыми примерами)