многопоточность — запуск асинхронной функции в переполнении стека

Можно ли создать некоторый класс 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();

4

Решение

Последние версии 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 приведет к тому, что контекст вызова будет ждать, пока результат не станет доступен, это может быть или не быть желательным, но служит хорошим примером.

5

Другие решения

PHP — синхронный язык. Практически все, что вы делаете, приводит к зависанию PHP во время его завершения, и это включает exec звонки, если вы хотите ответ.

Реализация, использующая основные элементы PHP, вероятно, потребует от вас exec или вызов cURL, а затем просмотрите ваш сервер для вывода позже в вашем скрипте.

Вы могли бы использовать PECL, о котором упоминал Дагон (Gearman), но я лично считаю, что с помощью менеджера очередей, такого как beanstalkd, управлять намного проще.

Вот это веб-сайт для beanstalkd.
А также Вот хорошая PHP-библиотека для beanstalkd (с некоторыми примерами)

2

По вопросам рекламы [email protected]