简体   繁体   English

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

[英]PHP multi-threading and returning values to parent thread

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. 我已经花了一个多小时了,在阳光下,我已经阅读了有关PHP中多线程的所有知识,而在将值返回给父线程时,我迷失了。 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. 尝试1)我创建了一个名为Results的类,使用一个静态方法为静态var数组分配了一个值,并使用另一个静态方法在代码执行完毕后返回所有数据,print_r显示了将数据添加到静态var数组,但是,当脚本执行完毕后,静态processData方法将返回一个空数组。

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. 尝试2)我从Results类中删除了静态元素,并将其放置在TaskManager中,使用匿名方法作为回调,我能够将值返回给TaskManager,但是再次,当代码执行完毕时,一个空阵列。

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. 尝试3)我创建了一个全局匿名方法用作回调,同样,值也传递给了该回调方法,但是您猜到了,代码完成执行后为空数组。

I am listing three attempts, but really, its been more like 20 attempts at this; 我列出了3次尝试,但实际上,这大概是20次尝试。 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}\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);

?>

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, eg the filing system or Memcache 使用其他共享存储机制,例如文件系统或Memcache
  • Use an inter-process communication system, such as Semaphore . 使用进程间通信系统,例如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) 我没有使用过,但是可能很有趣-理想情况下,您希望将消息发送到特定的PID(父任务)

Personally, I'd use a database, since this is a convenient mechanism to retrieve it anyway. 就个人而言,我会使用数据库,因为无论如何这都是检索数据库的便捷机制。

I suggest a look at socket_create_pair() . 我建议看一下socket_create_pair()

In the PHP manual is a very short & easy example of interprocess communication (IPC) between a fork()-parent and the child. 在PHP手册中,是fork()-parent和child之间的进程间通信(IPC)的非常简短的示例。

And using serialize() und unserialize() You could even transfer complex data types like arrays... 并使用serialize()unserialize()甚至可以传输诸如数组之类的复杂数据类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM