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.

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

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?