PHP多线程和向父线程返回值

PHP多线程和向父线程返回值,php,multithreading,Php,Multithreading,我已经做了一个多小时了,我已经阅读了所有关于PHP中多线程的文章,当涉及到将值返回到父线程时,我就不知所措了。实际上,我一直在强制使用各种不同的方法组合,将变量传递回父线程,但没有成功。我甚至不确定在这一点上是否可能 我尝试过使用返回、回调、匿名方法、调用的静态类/方法/变量,但什么都不起作用,当代码完成执行时,我继续得到一个空数组 尝试1)我创建了一个名为Results的类,使用一个静态方法为静态变量数组赋值,使用另一个静态方法在代码执行完毕时返回所有数据,但打印显示数据被添加到静态变量数组,

我已经做了一个多小时了,我已经阅读了所有关于PHP中多线程的文章,当涉及到将值返回到父线程时,我就不知所措了。实际上,我一直在强制使用各种不同的方法组合,将变量传递回父线程,但没有成功。我甚至不确定在这一点上是否可能

我尝试过使用返回、回调、匿名方法、调用的静态类/方法/变量,但什么都不起作用,当代码完成执行时,我继续得到一个空数组

尝试1)我创建了一个名为Results的类,使用一个静态方法为静态变量数组赋值,使用另一个静态方法在代码执行完毕时返回所有数据,但打印显示数据被添加到静态变量数组,脚本执行完毕后,静态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);

?>

我已经运行了您的代码,每次都成功调用了您的回调。但是,值得记住的是,这是多进程的,而不是多线程的。这意味着,对于添加到阵列中的每个项目,全局阵列在每个场合都是全新的,因此,当您添加新项目时,在每次推送之后,其中只有一个项目

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

这里有几个解决方案:

  • 使用数据库获取结果
  • 使用其他一些共享存储机制,例如归档系统或Memcache
  • 使用进程间通信系统,例如。我没有使用过它,但它可能很有趣-理想情况下,您希望将消息发送到特定的PID(父任务)

就我个人而言,我会使用数据库,因为这是一种方便的检索机制。

我建议看一下socket\u create\u pair()

在PHP手册中,有一个关于fork()父进程和子进程之间的进程间通信(IPC)的非常简单的例子


使用serialize()unserialize()甚至可以传输复杂的数据类型,比如数组…

我不知道它是否相关,但是
额外的
任务管理器::run()
@halfer中没有定义,这是可以的。@Havenard,很好的地方。尽管如此,我的IDE还是会抱怨,我个人还是会在调用之前将其设置为null。这里的问题是您不能在父进程和子进程之间共享数据。它们是不同的,不能看到彼此的数据或结构。如果这些是线程,您可以同步/加入它们。这就是为什么PHPs对你可能有用的原因。如果您想在N个进程之间共享数据,您需要为它们实现一种通信机制——共享内存、它们通过获取锁、数据库或类似内容访问的文件。或者简单地使用实际线程。