dongnanman9093
dongnanman9093
2015-09-15 15:10
浏览 114
已采纳

PHP Pthreads无法将值传递给线程中的子对象

So, I have about 100+ processes that I would like to make parallely executed. I am using PHP pthreads to do that.

The problem I have is that the threads start but they do not pass values to another object which is initialized within the thread. What I would like to do is the execute each of those child process in separate objects.

updated code

<?php 
ini_set('display_errors', 1);
define('DEBUG', true);

function pr($var) {
   if (!DEBUG) {
       return;
   }

   echo PHP_EOL;

   if ($var) {
      print_r($var);
   } else {
      var_dump($var);
   }

   echo PHP_EOL;
}

class A {

   //public $results = 1;

   function init() {
      pr(__CLASS__ . ' initailized');
   }

   function getResult() {
       return ($this->results);
   }
}

class B extends A {

   public $val;
   public $results = [
       'queries' => []
   ];

   function set($k, $v) {
      $this->{$k} = $v;
   }

   function init() {
      pr(__CLASS__ . ' initailized');
      parent::init();

      $this->results = ['some_value' => true];
   }
}

class Fetching extends Thread {

    function __construct() {

    }

   public function run() {
      $this->e = new B;
      $this->e->init();

      pr($this->e->getResult());
   }
}

$data = [
   'id' => 12345,
   'message' => 'some text here'
];

$thread = new Fetching();

$thread->start();
$thread->join();
pr($thread);

When I run $thread->results it outputs as NULL. But if I make it a string or int it works just fine.

图片转代码服务由CSDN问答提供 功能建议

因此,我有大约100多个我想并行处理的进程。 我使用PHP pthreads来做到这一点。

我遇到的问题是线程启动但它们没有将值传递给在线程中初始化的另一个对象。 我想要做的是在单独的对象中执行每个子进程。

更新的代码
 &lt;?php \  nini_set('display_errors',1); 
define('DEBUG',true); 
 
 
函数pr($ var){
 if(!DEBUG){
 return; 
} 
 
 echo PHP_EOL  ; 
 
 if($ var){
 print_r($ var); 
} else {
 var_dump($ var); 
} 
 
 echo PHP_EOL; 
} 
 
class A  {
 
 // public $ results = 1; 
 
函数init(){
 pr(__ CLASS__。'initailized'); 
} 
 
函数getResult(){
 return($  this-&gt; results); 
} 
} 
 
class B扩展A {
 
 public $ val; 
 public $ results = [
'queries'=&gt;  [] 
]; 
 
函数集($ k,$ v){
 $ this-&gt; {$ k} = $ v; 
} 
 
函数init(){
 pr  (__CLASS__。'initailized'); 
 parent :: init(); 
 
 $ this-&gt; results = ['some_value'=&gt; 获取扩展线程{
 
函数__construct(){
 
} 
 
公共函数run(){
 $ this-&gt; e =  new B; 
 $ this-&gt; e-&gt; init(); 
 
 pr($ this-&gt; e-&gt; getResult()); 
} 
} 
 
 $ data  = [
'id'=&gt;  12345,
'message'=&gt;  'some text'
]; 
 
 $ thread = new Fetching(); 
 
 $ thread-&gt; start(); 
 $ thread-&gt; join(); 
pr($ thread)  ); 
   
 
 

当我运行$ thread-&gt;结果时,它输出为NULL。 但是如果我把它变成一个字符串或int它就可以了。

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

2条回答 默认 最新

  • doutuo7126
    doutuo7126 2015-09-22 08:37
    已采纳

    Finally I found the answer. But I am not quite sure if its a correct behaviour. Your suggestions are welcome...

    What I was doing is creating a class variable $this->e and assigning it the child process object $this->e = new $object and then running the init() method. The init method returns a few queries back as class member variable i.e. $this->e->queries will have those queries assigned to it. The fix I found is that I should use it as a separate variable within the 'run' method of the Thread Object. Not as a class variable and Once I have the queries I can assign it to the class variable directly and call it after doing $thread->join() like $thread->queries and it works fine.

    In short - The class variables of the class extending to Thread does not support Objects within the run method.

    For more details below is the sample code. I have created two files. 1. Objects.php containing all objects and another one Processor.php. See below.

    Objects.php contains follow code.

    <?php
    
    class Controller {
    
       public $queries = [];
    
       public function init() {
    
       }
    
       public function set($key, $value) {
           $this->{$key} = $value;
           return $this;
       }
    
       function __destruct() {
           global $scriptStartTime;
           pr("Time taken for " . get_called_class() . " to execute = " .. executionTime($scriptStartTime, true));
       }
    }
    
    class SampleObject extends Controller {
    
      public function init() {
          parent::init();
          sleep(rand(0, 15));
          return $this->queries[] = 'INSERT INTO my_table (something) VALUES ("' . get_called_class() . '")';
      }
    }
    
    function pr($array) {
       echo PHP_EOL;
       print_r($array);
       echo PHP_EOL;
    }
    
    function executionTime($startTime, $text = false) {
       $time = @number_format(microtime(true) - $startTime, 3);
    
       $txt = 'seconds';
    
       if ($time > 60) {
          $time = @number_format($time / 60, 3);
          $txt = 'minutes';
       }
    
       if ($text) {
          $time = "{$time} {$txt}";
       }
    
       return $time;
    }
    

    Processor.php contains below code

    ini_set('display_errors', 1);
    
    require __DIR__ . DIRECTORY_SEPARATOR . 'Objects.php';
    
    ################ Processor #################
    
    class Processor extends \Thread {
    
        public function __construct($process) {
           $this->process = $process;
        }
    
        public function run() {
           //\Core\Autoloader::reload(); // reloading all autoloaders
           require __DIR__ . DIRECTORY_SEPARATOR . 'Objects.php';
           $scriptStartTime = microtime(true);
    
           # Dynamically creating objects for testing purpose.
           if (!class_exists($this->process['className'])) {
               eval("class " . $this->process['className'] . " extends SampleObject {}");
        }
    
           $object = (new $this->process['className']);
    
           # Set the default values that are common across all elements
           $object
                # Identity of thread
                ->set('name', $this->process['className'])
                # Options to carry the assigned values
                ->set('options', $this->process['options'])
                # The project details
                ->set('project', $this->project)
              ;
    
              $object->init();
    
              $this->queries = ($object->queries);
         }
    }
    
    $scriptStartTime = microtime(true);
    
    for ($i = 0; $i < 150; $i++) {
      $jobs[] = [
          'className' => 'Object_' . $i,
          'options' => []
      ];
    }
    
    $totalJobsToExecute = count($jobs);
    
    $i = 0;
    
    # Initalizing threads
    
    $threads = [];
    
    $project = [
       'id' => 12345,
       'title' => 'Some cool stuff'
    ];
    
    foreach ($jobs AS $process) {
       $i++;
    
       $proc = $process['className'];
       $threads[$proc] = new Processor($process);
       // In this sample code it works without PTHREADS_INHERIT_NONE, but with my code it doesn't    
       if ($threads[$proc]->start(PTHREADS_INHERIT_NONE)) {
          pr('Thread "' . $process['className'] . '" started');
       }
    }
    
    pr("Threads | Starting time = " . executionTime($scriptStartTime, true));
    
    $queries = [];
    
    foreach ($threads AS $thread) {
        if ($thread->join()) {
            $queries[] = $thread->queries;
        }
    }
    
    pr($queries);
    
    pr('Count of threads === ' . count($threads));
    pr("Threads time = " . executionTime($scriptStartTime, true));
    pr("Threads | Total Threads executed = ({$i}) out of (" . $totalJobsToExecute . ")");
    
    点赞 评论
  • duanhunlou7051
    duanhunlou7051 2015-09-17 04:51

    I think there's your problem:

    $threads[$i]->start(PTHREADS_INHERIT_NONE);
    

    You might need PTHREADS_INHERIT_CLASSES to be able to access the class ChildProcess.


    Because of the zend_heap error (I can't reproduce it): Which version of PHP and pthreads are you using?

    点赞 评论

相关推荐