3

Help me understand how exactly Pool::collect works.

Pool::collect — Collect references to completed tasks

public void Pool::collect ( Callable $collector )

What I assume was: Pool::collect registers a function, which will be called after each \Threaded $task is completed. So, I did:

<?php
$pool = new Pool(4);
$pool->collect($collector);
$pool->submit(new Task);

Didn't work. But the following does:

<?php
$pool = new Pool(4);
$pool->submit(new Task);
$pool->collect($collector);

So, I guess what Pool::collect does is: attaches the $collector to each \Threaded $task previously submitted.

Now, when exactly the $collector is called? I assume was called after Threaded::run() is completed. Wrong again.

<?php
class Task extends Threaded {
    public function run () { echo "Task complete\n"; }
}

$collector = function (\Task $task) {
    echo "Collect task\n";
    return true;
};

$pool = new Pool(4);
$pool->submit(new Task);
$pool->collect($collector);
$pool->shutdown();

Outputs:

Collect task
Task complete

$collector is called before Threaded::run() is completed.


The documentation doesn't say much. Doesn't event say that the $collector must return a boolean value. I didn't know that.

I was trying to use Pool::collect as kind of a callback after each $task is completed. I think I'm in the wrong path.

Edit 1. What about this attempt?

Community
  • 1
  • 1
luistar15
  • 163
  • 1
  • 9

2 Answers2

4

Pool::collect traverses a list of objects passing each one to the $collector.

The $collector function should return true when the engine can destroy the reference to the Threaded object in the work list.

In PHP7

The ::collect functionality was moved to Worker, though it's still exposed by Pool for utility.

There are two lists, one list of items ready to be executed, and another of items that have been executed (or is currently being executed).

Pool::collect traverses the second list, items that have been executed (or is currently being executed).

Pool::collect returns the number of items still left in the garbage list for all Worker objects in the Pool to aid with scheduling garbage collection.

PHP7 Code

<?php
$pool = new Pool(4);

while (@$i++<10) {
    $pool->submit(new class($i) extends Threaded {
        public function __construct($id) {
            $this->id = $id;
        }

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

        public $id;
    });
}

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

$pool->shutdown();
?>

Will yield something like:

Hello World from 1
Hello World from 2
Hello World from 3
Hello World from 4
Hello World from 8
Collecting 1
Hello World from 7
Hello World from 5
Collecting 5
Hello World from 6
Collecting 9
Collecting 2
Collecting 6
Collecting 10
Hello World from 9
Collecting 3
Collecting 7
Collecting 4
Hello World from 10
Collecting 8
Collecting 5
Collecting 10
Joe Watkins
  • 17,032
  • 5
  • 41
  • 62
  • This example doesn't work with the latest pthreads oh PHP7. `Collectable` is an interface now and even if I update it I run into this issue http://stackoverflow.com/questions/40854207/using-pool-class-in-php7-pthreads-extension – martin Nov 29 '16 at 10:26
0

You missed the audit cycle. Task can not be completed immediately, so at first the collect function do not receive positive result. Several times need to check, it requires a cycle.

In the example if infinite is true, always 4 tasks working. Otherwise, if size of queue is equal with pool size (4), it is over, you can exit the loop.

<?php

class Task extends \Threaded
{

    protected $result;
    protected $completed = false;

    public function run()
    {
        echo "Task complete\n";
        $this->result = md5(rand(1, 2000));
        sleep(rand(1, 5));
        $this->completed = true;
    }

    public function isCompleted()
    {
        return $this->completed;
    }

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

$infinite = false;
$poolSize = 4;
$queue = array();

$pool = new \Pool($poolSize);
$pool->submit(new Task);
$pool->submit(new Task);
$pool->submit(new Task);
$pool->submit(new Task);


do {
    if($infinite === true){
        $queue = array();
    }

    $pool->collect(function (\Task $task) use (&$queue) {
        if ($task->isCompleted()) {
            echo "Collect task\n";
            $queue[] = $task->getResult();

            return true;
        } else {
            echo "task not complete\n";

            return false;
        }
    });

    $size = sizeof($queue);
    if ($size > 0) {

        echo $size . " result\n";
        print_r($queue);

        if($infinite === true) {
            for ($m = 0; $m < $size; $m++) {
                $pool->submit(new Task);
            }
        } else{
            if($size == $poolSize){
                break;
            }
        }
    }

    usleep(100000);

} while (true);
$pool->shutdown();
Laszlo Malina
  • 43
  • 1
  • 5