PHP多线程并将值返回到父线程

时间:2013-11-17 22:02:31

标签: php multithreading

我已经在这里工作了一个多小时,我已经阅读了关于PHP中多线程的所有内容,当涉及到将值返回到父线程时,我迷失了。我实际上已经粗暴地强制使用不同的方法组合,以便将变量传递回父线程,但没有成功。我甚至不确定此时是否可能。

我已经尝试了带有返回,回调,匿名方法,调用的静态类/方法/变量,并且没有任何工作,我在代码完成执行时继续得到一个空数组。

尝试1)我创建了一个名为Results的类,其中一个静态方法为静态var数组赋值,另一个静态方法在代码执行完毕后返回所有数据,print_r显示数据为但是,当脚本完成执行静态processData方法时,返回一个空数组。

尝试2)我从Results类中删除了静态元素,并将它放在TaskManager中,使用匿名方法作为回调,我能够将值返回给TaskManager,但是,当代码完成执行时,一个空数组。

尝试3)我创建了一个全局匿名方法用作回调,同样,值被传递给回调方法,但是你猜对了,代码执行完毕后是空数组。

我列出了三次尝试,但实际上,它更像是20次尝试;我在我的智慧结束,任何帮助都非常感谢。

以下是我一直在使用的代码。

<?php

/**
 * author : Marc Quinton / April 2008.
 *
 *  a simple task management framework using pcntl_fork, pcntl_wait.
 *
 *  - see at bottom for a sample usage.
 *  - you shoud overring Task class (SleepingClass is an example), and manage them in a pool, using taskManager
 */

error_reporting(E_ALL);

class Results {
    var $datas = array();

    public function data($data)
    {
        $this->datas[] = $data;
    }

    public function processResults()
    {
        foreach($this->datas as $data)
        {
            print_r($data);
        }
    }
}

class Task {

    protected $data;

    protected $pid;
    protected $ppid;

    function __construct(){
    }

    function fork(){
        $pid = pcntl_fork();
        if ($pid == -1)
            throw new Exception ('fork error on Task object');
        elseif ($pid) {
            # we are in parent class
            $this->pid = $pid;
            # echo "< in parent with pid {$his->pid}\n";
        } else{
            # we are is child
            $this->run();
        }
    }

    function run(){
        # echo "> in child {$this->pid}\n";
        # sleep(rand(1,3));
        $this->ppid = posix_getppid();
        $this->pid = posix_getpid();
    }

    # call when a task in finished (in parent)
    function finish(){
        echo "task finished {$this->pid}\n";
    }

    function pid(){
        return $this->pid;
    }
}

class SleepingTask extends Task{
    public $mybl;
    public $data;
    public $cback;

    function __construct($bl, $cb){
        $this->cback = $cb;
        $this->mybl = $bl;
    }

    function run(){
        global $callback;

        parent::run();

        echo "My BL ID: " . $this->mybl . " /END BL ID\n";

        $callback(array('whoa' => $this->mybl));

        sleep(rand(1,2));

        exit(0);
    }
}

class TaskManager{

    protected $pool;
    protected $datas = array();

    function __construct(){
        $this->pool = array();
    }

    function add_task($task){
        $this->pool[] = $task;
    }

    function run(){

        foreach($this->pool as $task){
            $task->fork();
        }

        # print_r($this);
        # sleep(60);

        while(1){
            echo "waiting\n";
            $pid = pcntl_wait($extra);
            if($pid == -1)
                break;

            echo ": task done : $pid\n";
            $this->finish_task($pid);
        }

        echo "processes done ; exiting\n";
    }

    function finish_task($pid){
        if($task = $this->pid_to_task($pid)) {
            $task->finish();
        }
    }

    function pid_to_task($pid){
        foreach($this->pool as $task){
            if($task->pid() == $pid)
                return $task;
        }
        return false;
    }
}

$datas = array();
$callback = function ($data) {
    print_r($data);
    global $datas;
    $datas[] = $data;
};

$manager = new TaskManager();

for($i=0 ; $i<10 ; $i++)
    $manager->add_task(new SleepingTask($i, $callback));

$manager->run();

print_r($datas);

exit(0);

?>

2 个答案:

答案 0 :(得分:3)

我运行了你的代码,每次都成功调用你的回调。但是,值得注意的是,这是多过程,而不是多线程。这意味着对于添加到数组中的每个项目,全局数组在每种情况下都是全新的,因此当您添加新项目时,每次推送后只有一个项目。

此外,每个添加都发生在子进程中,因此当控制恢复到父进程时,全局数组也是新的,因此其中没有正确的内容。

这里有一些解决方案:

  • 使用数据库获取结果
  • 使用其他一些共享存储机制,例如文件系统或Memcache
  • 使用进程间通信系统,例如Semaphore。我没有使用它,但它可能是有意义的 - 理想情况下你想要发送消息到特定的PID(父任务)

就个人而言,我会使用数据库,因为无论如何这都是一种方便的机制来检索它。

答案 1 :(得分:0)

我建议看一下 socket_create_pair()

在PHP手册中是一​​个很短的&amp; fork() - 父级和子级之间的进程间通信(IPC)的简单示例。

使用序列化()反序列化()您甚至可以传输复杂的数据类型,例如数组......