Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running async function in php

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();
like image 388
vlio20 Avatar asked Dec 02 '14 20:12

vlio20


1 Answers

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.

like image 133
Joe Watkins Avatar answered Oct 01 '22 01:10

Joe Watkins