php7 pthreads鸡肋_在PHP7 pthreads扩展中使用Pool类

I took the most basic demo of pthreads PHP7 extension that uses Pool class (this demo https://github.com/krakjoe/pthreads#polyfill) and extended it a little so I can grab results from the thread (or at least I think I can):

$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();

What's confusing me is that it sometimes doesn't get the result for all tasks:

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

Now two lines with 5 10 and 6 12 are missing but I don't understand why. This happens only sometimes (maybe 1/10 runs).

It looks like the original demo is for the older version of pthreads because there's Collectable interface which is now automatically implemented by Threaded if I'm not mistaken.

Then the readme says:

The Pool::collect mechanism was moved from Pool to Worker for a more robust Worker and simpler Pool inheritance.

So I guess I'm doing something wrong.

Edit: I took the example from How does Pool::collect works? and updated it to work with latest pthreads and current PHP7 but the result is the same. It looks like it's not able to collect results from the last threads that are executed.

$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();

This outputs the following which is clearly not collecting all threads:

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

解决方案

As you have quite correctly noted, the code you have copied targets pthreads v2 (for PHP 5.x).

The problem boils down to the fact that the garbage collector in pthreads is not deterministic. This means it will not behave predictably, and so it cannot be reliably used in order to fetch data from the tasks that have been executed by the pool.

One way you could fetch this data would be to pass in Threaded objects into the tasks being submitted to the pool:

$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);

}

There are a few things to note about the above code:

Collectable (which is now an interface in pthreads v3) is implemented by the Threaded class already, so there's no need to implement it yourself.

Once a task has been submitted to the pool, it is already considered to be garbage, and so there is no need to handle this part yourself. Whilst you still have the ability to override the default garbage collector, this should not be needed in the vast majority of cases (including yours).

I still invoke the collect method (in a loop that blocks the main thread until all tasks have finished executing) so that the tasks can be garbage collected (using pthreads' default collector) to free up memory whilst the pool is executing tasks.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值