is it possible to create some php class which can run functions asynchronously? Here is what I have done so far:
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;
}
}
Here is how I want to call it:
$worker = new Worker();
$worker->setAsyncFunction(foo, ["a", "b"]);
$worker::start();
Advertisement
Answer
Recent versions of pthreads support closures as members, making the code very simple:
<?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("%sn", $greeting);
}, ["Hello World"]);
$background->start();
$background->join();
function named($greeting) {
printf("%sn", $greeting);
}
$background = new Background("named", ["Goodbye World"]);
$background->start();
$background->join();
?>
However, this is horrible, it’s hard to imagine any function that is so hungry that it requires a thread of it’s own.
You have started down the right path with the thought that you should reuse the context and create a worker thread, pthreads has all of this built in.
More sensible code using built in classes looks more like:
<?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("%sn", $greeting);
}, ["Hello World"]));
$pool->shutdown();
?>
But this still doesn’t deal with a return value. I’ll assume that you want to retrieve the result of calls made using the Pool
, in that case the code looks more like:
<?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("%sn", $greeting);
}, ["Hello World"]);
$pool->submit($call);
echo $call->getResult();
$pool->shutdown();
?>
As you can see, a call to Background::getResult
will result in the calling context waiting until a result is available, this may or may not be desirable, but makes for a good example.