dongxi7704 2013-11-17 22:02
浏览 55
已采纳

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

I have been at this for over an hour, I have read everything under the sun about multi-threading in PHP, and I am lost when it comes to returning values to the parent thread. I have been practically brute forcing different combinations of ways I can come up with to pass variables back to the parent thread with zero success. I am not even sure if it is possible at this point.

I have tried static classes/methods/vars with a return, callbacks, anonymous methods, invokes, and nothing is working, I continue to get an empty array when the code finishes executing.

Attempt 1) I created a class called Results, with a static method that assigned a value to a static var array, with another static method to return all of the data when the code was finished executing, a print_r showed the data being added to the static var array, however, when the script was finished executing the static processData method returned an empty array.

Attempt 2) I removed the static elements from the Results class, and placed it in the TaskManager, using an anonymous method as a callback, I was able to return values to the TaskManager, but again, when the code was finished executing, an empty array.

Attempt 3) I created a global anonymous method to use as a callback, again, values are passed to the callback method, but you guessed it, empty array when the code was finished executing.

I am listing three attempts, but really, its been more like 20 attempts at this; I am at my wits end, any help at all is greatly appreciated.

Here is the code I have been working with.

<?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}
";
        } else{
            # we are is child
            $this->run();
        }
    }

    function run(){
        # echo "> in child {$this->pid}
";
        # 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}
";
    }

    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
";

        $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
";
            $pid = pcntl_wait($extra);
            if($pid == -1)
                break;

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

        echo "processes done ; exiting
";
    }

    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条回答 默认 最新

  • drfcaw7460 2013-11-17 22:31
    关注

    I've run your code, and your callback is being called successfully each time. However, it's worth bearing in mind that this is multi-process, not multi-threading. That means that for each item added to the array, the global array is brand new on each occasion, and so when you add a new item, there is only one item in there after each push.

    Furthermore, each of those additions occurs in a child process, so when control reverts to the parent process, the global array there is also new, and so there is correctly nothing in it.

    There are a few solutions here:

    • Use a database for your results
    • Use some other shared storage mechanism, e.g. the filing system or Memcache
    • Use an inter-process communication system, such as Semaphore. I've not used this, but it might be of interest - ideally you want to send messages to a specific PID (the parent task)

    Personally, I'd use a database, since this is a convenient mechanism to retrieve it anyway.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作