Skip to content

Conversation

@leocavalcante
Copy link
Member

This PR introduces Futures as part of Swoole's standard library features.

Futures are abstractions on top of Coroutines providing alternative syntax for building concurrent programs with Swoole.

Main differences from Coroutines are:

Futures are lazy

They don't evaluate until you call await:

$future = Future\async(static function (): void {
    echo "are lazy\n";
});

Coroutine::create(static function (): void {
    echo 'Futures ';
});

echo $future->await();

Futures can return values

The Channel handling is done under the hood:

$future = Future\async(static function (): string {
    return Http\get('https://httpbin.org/get')->getBody();
});

echo $future->await();

Futures propagates exceptions

$future = Future\async(static function (): string {
    throw new RuntimeException('Futures propagates exceptions');
});

try {
    $future->await();
} catch (Throwable $e) {
    echo $e->getMessage();
}

Futures synchronization is similar

It uses Coroutine::join under the hood:

$future1 = \Swoole\Future::create(static function () {
    return \Swoole\Coroutine\Http\get('https://httpbin.org/delay/2')->getBody();
});

$future2 = \Swoole\Future::create(static function () {
    return \Swoole\Coroutine\Http\get('https://httpbin.org/delay/2')->getBody();
});

echo implode(PHP_EOL, \Swoole\Future::join([$future1, $future2]));

@leocavalcante leocavalcante added enhancement New feature or request rfc Request for comments labels Dec 26, 2021
@leocavalcante leocavalcante self-assigned this Dec 26, 2021
@deminy deminy self-requested a review December 29, 2021 06:33
return new self($func);
}

public static function join(array $futures, float $timeout = -1): array

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your implementation is good and readable. But, I would put some minor tweaks (not functional ones, just a different style and one less variable to decrement) into it:

   public static function join(array $futures, float $timeout = -1): array
    {
        $ch = new Channel(count($futures));

        Coroutine::join(array_map(static function (Future $future) use ($ch): int {
            return $future->run($ch);
        }, $futures));

        $rets = [];
        while ($ret = $ch->pop($timeout)) {
            if ($ret instanceof Throwable) {
                throw $ret;
            }

            $rets[] = $ret;
        }

        return $rets;
    }

@johanjanssens
Copy link

@leocavalcante This is really nice work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request rfc Request for comments

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants