Runtime (jubianchi\async\runtime)

jubianchi\async\runtime::await(mixed $generatorOrValue) : mixed

await takes a generator or a value as its single parameter.

When it gets a generator it will walk through it until its end. It will return the generator return value.

Given the following script where the producer function returns a generator:

<?php

require_once __DIR__ . '/../../vendor/autoload.php';

use function jubianchi\async\runtime\{await};

function producer($prefix, $length) : \generator {
    for ($i = 0; $i < $length; $i++) {
        echo $prefix . '-' . $i . PHP_EOL;
        yield;
    }

    return __LINE__;
}

var_dump(
    await(
        producer(__LINE__, 5)
    )
);

If we run this script we get the following output:

18-0
18-1
18-2
18-3
18-4
int(13)

The await call will walk until the end of the generator and resolve to the the generator return value.

jubianchi\async\runtime::all(...$generators) : \generator

all takes one or more generator as its arguments and will walk concurrently through each of them. It will return a generator which will resolve to an array containing all the generators' return values.

Given the following script where the producer function returns a generator:

<?php

require_once __DIR__ . '/../../vendor/autoload.php';

use function jubianchi\async\runtime\{await, all};

function producer($prefix, $length) : \generator {
    for ($i = 0; $i < $length; $i++) {
        echo $prefix . '-' . $i . PHP_EOL;
        yield;
    }

    return $prefix . '-' . __LINE__;
}

var_dump(
    await(
        all(
            producer(__LINE__, 5),
            producer(__LINE__, 2)
        )
    )
);

If we run this script we get the following output:

19-0
20-0
19-1
20-1
19-2
19-3
19-4
array(2) {
  [0]=>
  string(5) "19-13"
  [1]=>
  string(5) "20-13"
}

As you can see, the all call will walk through all generators alternately and resolve to an array containing all the generators return values in the same order as the arguments passed to all.

What's interesting here is that each yield is an opportunity for the runtime to switch task.

jubianchi\async\runtime::race($first, $second, ...$generators) : \generator

race takes several generator as its arguments and will walk concurrently through each of them. It will return a generator which will resolve with the value of the first finished generator.

Given the following script where the producer function returns a generator:

<?php

require_once __DIR__ . '/../../vendor/autoload.php';

use function jubianchi\async\runtime\{await, race};

function producer($prefix, $length) : \generator {
    $cancel = false;

    for ($i = 0; $i < $length && $cancel === false; $i++) {
        echo $prefix . '-' . $i . PHP_EOL;
        $cancel = (bool) yield;
    }

    if ($cancel === true) {
        echo $prefix . '-canceled' . PHP_EOL;
    }

    return $prefix . '-' . __LINE__;
}

var_dump(
    await(
        race(
            producer(__LINE__, 5),
            producer(__LINE__, 2)
        )
    )
);

If we run this script we get the following output:

25-0
26-0
25-1
26-1
25-2
25-canceled
string(5) "26-19"

race will handle the generators in the same way all does. The only difference is that it will immediately stop once one of the generator is finished. It will then resolve to the this generator return value.

What's interesting here is that each generator producer will receive (through the yield) a boolean indicating whether it should stop or not (here, we used the $cancel variable).

jubianchi\async\runtime::some(int $howMany, ...$generators) : \generator

some takes several generator as its last arguments and a number as its first argument. It will walk concurrently through each of the generators and return a generator as soon as the given number of generators are over.

Given the following script where the producer function returns a generator:

<?php

require_once __DIR__ . '/../../vendor/autoload.php';

use function jubianchi\async\runtime\{await, some};

function producer($prefix, $length) : \generator {
    $cancel = false;

    for ($i = 0; $i < $length && $cancel === false; $i++) {
        echo $prefix . '-' . $i . PHP_EOL;
        $cancel = (bool) yield;
    }

    if ($cancel === true) {
        echo $prefix . '-canceled' . PHP_EOL;
    }

    return $prefix . '-' . __LINE__;
}

var_dump(
    await(
        some(
            2,
            producer(__LINE__, 5),
            producer(__LINE__, 10),
            producer(__LINE__, 2)
        )
    )
);

If we run this script we get the following output:

26-0
27-0
28-0
26-1
27-1
28-1
26-2
27-2
26-3
27-3
26-4
27-4
27-canceled
array(2) {
  [0] =>
  string(5) "26-19"
  [2] =>
  string(5) "28-19"
}

some has a similar behavior than the race function. The only difference is that it will wait for a given number of generators to finish. It will return a generator which will resolve to an array containing all the generators' return values.