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 有了解d3和topogram.js库的吗?有偿请教
  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 unity第一人称射击小游戏,有demo,在原脚本的基础上进行修改以达到要求
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line