在php中运行异步功能

时间:2014-12-02 20:44:12

标签: php multithreading asynchronous

是否可以创建一些可以异步运行函数的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();

2 个答案:

答案 0 :(得分:5)

最新版本的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的调用将导致调用上下文等待,直到结果可用,这可能是也可能不是,但这是一个很好的例子。

答案 1 :(得分:2)

PHP是一种同步语言。几乎所做的任何事情都会导致PHP在完成时挂起,如果你想要一个响应,它还包括exec次调用。

使用核心PHP元素的实现可能需要您执行一些exec或cURL调用,然后在脚本中稍后浏览服务器以获取输出。

你可以使用Dagon提到的PECL(Gearman),但我个人认为使用像beanstalkd这样的队列管理器更容易管理。

Here是beanstalkd的网站。 here是一个很好的beanstalkd的PHP库(有一些例子)