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.