2016-11-28 29 views
3

我采用了pthread PHP7扩展的最基本演示,它使用了Pool类(此演示https://github.com/krakjoe/pthreads#polyfill),并对其进行了一些扩展,以便可以从线程中获取结果(或者至少我认为我可以):在PHP7中使用Pool类pthreads扩展

$pool = new Pool(4); 

foreach (range(1, 8) as $i) { 
    $pool->submit(new class($i) extends Threaded 
    { 
     public $i; 
     private $garbage = false; 

     public function __construct($i) 
     { 
      $this->i = $i; 
     } 

     public function run() 
     { 
      echo "Hello World\n"; 
      $this->result = $this->i * 2; 
      $this->garbage = true; 
     } 

     public function isGarbage() : bool 
     { 
      return $this->garbage; 
     } 
    }); 
} 

while ($pool->collect(function(Collectable $task) { 
    if ($task->isGarbage()) { 
     echo $task->i . ' ' . $task->result . "\n"; 
    } 
    return $task->isGarbage(); 
})) continue; 

$pool->shutdown(); 

什么是困惑我的是,它有时不能得到结果所有任务:

Hello World 
Hello World 
Hello World 
Hello World 
Hello World 
1 2 
2 4 
Hello World 
Hello World 
3 6 
Hello World 
7 14 
4 8 
8 16 

现在两行5 106 12失踪,但我不明白为什么。这种情况有时只会发生(可能是1/10次)。

它看起来像原来的演示是为pthreads的旧版本,因为有Collectable接口,如果我没有弄错,现在自动实现Threaded

然后自述说:

泳池::收集机制,从游泳池到工人搬到了一个更强大的工人,简单的池继承。

所以我想我做错了什么。

编辑:我接过例如,从How does Pool::collect works?和更新,它与最新的并行线程和电流PHP7工作,但结果是一样的。它看起来不能从最后执行的线程收集结果。

Hello World from 1 
Collecting 1 
Hello World from 2 
Collecting 2 
Hello World from 3 
Collecting 3 
Hello World from 4 
Collecting 4 
Hello World from 5 
Collecting 5 
Hello World from 6 
Hello World from 7 
Collecting 6 
Collecting 7 
Hello World from 8 
Hello World from 9 
Hello World from 10 

回答

1

正如你已经相当正确地指出,你的代码已经复制目标并行线程V2(对于PHP 5.x的):

$pool = new Pool(4); 

while (@$i++<10) { 
    $pool->submit(new class($i) extends Thread implements Collectable { 
     public $id; 
     private $garbage; 

     public function __construct($id) { 
      $this->id = $id; 
     } 

     public function run() { 
      sleep(1); 
      printf(
       "Hello World from %d\n", $this->id); 
      $this->setGarbage(); 
     } 

     public function setGarbage() { 
      $this->garbage = true; 
     } 

     public function isGarbage(): bool { 
      return $this->garbage; 
     } 

    }); 
} 

while ($pool->collect(function(Collectable $work){ 
    printf(
     "Collecting %d\n", $work->id); 
    return $work->isGarbage(); 
})) continue; 

$pool->shutdown(); 

这是下面的显然不是收集所有线程的输出。

问题归结为pthreads 中的垃圾收集器不是确定性的。这意味着它不会有可预测的表现,因此无法可靠地使用它来从池中执行的任务中获取数据。你可以获取这个数据

一种方法是在Threaded物体插入任务通过被提交到池:

<?php 

$pool = new Pool(4); 
$data = []; 

foreach (range(1, 8) as $i) { 
    $dataN = new Threaded(); 
    $dataN->i = $i; 

    $data[] = $dataN; 

    $pool->submit(new class($dataN) extends Threaded { 
     public $data; 

     public function __construct($data) 
     { 
      $this->data = $data; 
     } 

     public function run() 
     { 
      echo "Hello World\n"; 
      $this->data->i *= 2; 
     } 
    }); 
} 

while ($pool->collect()); 

$pool->shutdown(); 

foreach ($data as $dataN) { 
    var_dump($dataN->i); 
} 

有几件事情需要注意上面的代码:

  • Collectable(现在是pthreads v3中的一个接口)已由Threaded类实现,因此不需要自己实现它。
  • 一旦一个任务被提交到池中,它就已经被认为是垃圾,所以不需要自己处理这个部分。虽然您仍然可以覆盖默认的垃圾收集器,但绝大多数情况下(包括您的)都不需要这样做。
  • 我仍然调用collect方法(在阻止主线程的循环中,直到所有任务完成执行),以便在池正在执行任务时可以垃圾收集任务(使用pthreads的默认收集器)以释放内存。