5

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();
9
  • i would spawn a new php script with exec Commented Dec 2, 2014 at 21:08
  • @Dagon can you post some code? Commented Dec 2, 2014 at 21:08
  • exec('php script.php') Commented Dec 2, 2014 at 21:09
  • but it is not dynamic this way. Commented Dec 2, 2014 at 21:10
  • 2
    @Dagon From the PHP manual: Note: If a program is started with this function, in order for it to continue running in the background, the output of the program must be redirected to a file or another output stream. Failing to do so will cause PHP to hang until the execution of the program ends. - Is that your definition of async? Commented Dec 2, 2014 at 21:40

2 Answers 2

5

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("%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();
?>

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("%s\n", $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("%s\n", $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.

Sign up to request clarification or add additional context in comments.

Comments

2

PHP is a synchronous language. Almost anything you do will cause PHP to hang while it finishes, and that includes exec calls if you want a response.

An implementation using core PHP elements will probably require you to do some exec or cURL call and then browse your server for the output later in your script.

You could use the PECL that Dagon mentioned (Gearman) but I personally think that using a queue manager like beanstalkd is much easier to manage.

Here is the website for beanstalkd. And here is a good PHP library for beanstalkd (with some examples)

4 Comments

There's no multithreading class in a default PHP installation that I know of? Beanstalkd also has the advantage of not being reliant on PHP and supports multiple servers. You could have workers that take jobs off the queue in beanstalkd that are written in almost any language. Essentially, it's quicker and more diverse.
Part of a PECL extension: php.net/manual/en/pthreads.installation.php - You will have to install this library yourself.
OK, so what? Are there any possible issues with that?
My only reservation with using PECL extensions is that you have to keep them up to date, and that might not always agree with keeping PHP up to date. You are really relying on the developers of a community extension to keep their software up to date so you can update PHP. By all means, don't let me stop you from using pthreads if you are sure it's the right thing for you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.