O grande poder da Swoole reside na execução simultânea de tarefas usando as famosas Corrotinas. Já que existe bastante teoria sobre como isso funciona, vamos agora explorar como se aplica na prática.
Para criar Corotinas no Swoole, você pode usar o método estático create(), passando a função que deseja executar:
use Swoole\\Coroutine;
Coroutine::create(static function(): void {
echo "Hello, World!\\n"; // Hello, World!
});
Observe que a função sempre retornará void. Se quiser extrair um resultado de uma Corrotina, você pode usar Channels:
$channel = new Channel();
Coroutine::create(static function () use ($channel): void {
$channel->push("Hello, World!\\n"); // Hello, World!
});
echo $channel->pop();
Os canais funcionam como filas FIFO. Você adiciona um conteúdo com push e recupera com pop. Você pode utilizar a mesma Channel em mais de uma Corrotina.
$channel = new Channel();
Coroutine::create(static function () use ($channel): void {
$channel->push("Hello, ");
});
Coroutine::create(static function () use ($channel): void {
$channel->push("World!\\n");
});
echo $channel->pop() . $channel->pop(); // Hello, World!
Lembre-se que a ordem é baseada no momento em que a Corrotina termina, não na ordem em que é criada.
$channel = new Channel();
Coroutine::create(static function () use ($channel): void {
Coroutine::sleep(1);
$channel->push("World!\\n"); // World vem primeiro no código, mas com delay de 1s
});
Coroutine::create(static function () use ($channel): void {
$channel->push("Hello, ");
});
echo $channel->pop() . $channel->pop(); // Hello, World!
Os canais são uma maneira segura e eficiente de compartilhar dados entre Corrotinas sem a necessidade de compartilhar memória, usando uma técnica conhecida como message-passing.
No entanto, ainda é possível compartilhar a referência de uma variável para uma Corrotina com o objetivo de alterar seu valor com o resultado da Corrotina:
$message = "";
Coroutine::create(static function() use (&$message): void {
Coroutine::sleep(1);
$message = "Hello, World!\\n";
});
echo $message; // ""
<aside> ⚠️ É claro que isso não vai funcionar.
</aside>
Afinal, o código que segue a criação da Coroutine, com o echo, não sabe quando a Coroutine terminou de executar.
Para aguardar a execução de uma Coroutine, podemos usar WaitGroups!
$wg = new WaitGroup();
$message = "";
Coroutine::create(static function() use ($wg, &$message): void {
$wg->add();
Coroutine::sleep(1);
$message = "Hello, World!\\n";
$wg->done();
});
$wg->wait(); // Agora sim, o WG espera todas as corrotinas que usam ele
echo $message; // Hello, World!