Introdução ao Swoole, framework PHP assíncrono baseado em corrotinas \| TreinaWeb               Promoção no ar   Matricule-se agora e garanta **54% de desconto**  

  Termina em   Tempo restante da oferta: 20 Horas 

 22 Min 

 33 Seg 

   Tempo restante da oferta: 20 22 33 

  [Assinar →](https://www.treinaweb.com.br/checkout/pagamento/plano/anual?cupom=TW-SCLIENTE26) 

   [                ](https://www.treinaweb.com.br)  Explorar  

 [ Quanto custa? ](#assinatura) [ FAQ ](https://www.treinaweb.com.br#faq) [Matricule-se](#assinatura) [ Entrar ](https://www.treinaweb.com.br/login) 

     [ Início ](https://www.treinaweb.com.br) [ Artigos ](https://www.treinaweb.com.br/blog) Introdução ao Swoole, framework PHP assíncrono baseado em corrotinas  [ PHP ](https://www.treinaweb.com.br/blog/categoria/php) 

# Introdução ao Swoole, framework PHP assíncrono baseado em corrotinas

 Uma Introdução ao Swoole, framework PHP assíncrono baseado em corrotinas e comparação dele com o modelo tradicional que usa um servidor web (nginx, apache etc) com PHP-FPM.

 [ Kennedy Tedesco ](https://www.treinaweb.com.br/blog/autor/kennedy-tedesco) 7 anos atrás

  ![](https://dkrn4sk0rn31v.cloudfront.net/uploads/2019/11/12132017/introducao-swoole.png)  

 O [Swoole](https://www.swoole.co.uk/) é um [framework](https://www.treinaweb.com.br/blog/para-que-serve-um-framework/ "framework") de programação assíncrona para [PHP](https://www.treinaweb.com.br/blog/o-que-e-php/ "O que é PHP?") e já se posiciona como uma opção estável e confiável para se desenvolver de forma concorrente com alta performance e uso equilibrado de recursos. Ele implementa I/O assíncrono orientado a eventos baseado no padrão Reactor (o mesmo utilizado por ReactPHP, NodeJS, Netty do Java, Twisted do Python entre outros). O Swoole é escrito em C e disponibilizado como uma extensão para PHP.

O Swoole permite que escrevamos aplicações altamente performáticas e concorrentes usando TCP, UDP, Unix Socket, HTTP e WebSockets sem que precisemos ter grandes conhecimentos de baixo nível sobre assincronismo e/ou sobre o kernel do Linux. Ele fornece uma completa [API](https://www.treinaweb.com.br/blog/o-que-e-uma-api/ "API") de alto nível com foco na produtividade. O Swoole é usado em grandes projetos enterprises, principalmente na China sendo Baidu (maior portal de busca da China) e Tencent (um dos maiores portais de serviços da China) os principais casos de uso.

É muito importante e recomendado que antes de continuar aqui, você leia o artigo sobre [Introdução à programação assíncrona em PHP usando o ReactPHP](https://www.treinaweb.com.br/blog/introducao-a-programacao-assincrona-em-php-usando-o-reactphp/), pois ele vai te introduzir alguns importantes conceitos de como é o modelo tradicional síncrono de se desenvolver em PHP e como funciona o modelo assíncrono usando o padrão Reactor.

[  ![PHP Avançado](https://d2knvm16wkt3ia.cloudfront.net/assets/svg-icon/php.svg)   Curso PHP Avançado Conhecer o curso ](https://www.treinaweb.com.br/curso/php-avancado)

**Para o que veio e para o que não veio o Swoole**

O Swoole não veio para substituir a abordagem tradicional e síncrona de como a maioria do projetos em PHP são escritos. Ao contrário disso, ele veio pra suprir os outros casos de uso como, por exemplo, a criação de servidores TCP, RPC, Websockets etc. Ele veio para resolver o problema de servidores que precisem de alta concorrência. Para se ter ideia, um único servidor escrito usando o Swoole consegue lidar com 1 milhão de conexões (C1000K). Também podemos dizer que o Swoole veio para que você não precise mudar toda sua stack e linguagem para resolver as necessidades acima listadas.

**Muitas formas de se atingir assincronismo**

Síncrono ou assíncrono é sobre o fluxo de execução. É possível atingir assincronismo de diversas formas como, por exemplo, uma fila de mensagens (Amazon SQS, Redis etc) onde você a alimenta com as tarefas (jobs) e no seu servidor você tem uma determinada quantidade de *worker processes* consumindo essa fila e executando as tarefas de forma concorrente e/ou paralela (a depender dos núcleos da CPU).

Também é possível atingir assincronismo com Ajax, lembra de requisição assíncrona onde é possível enviar a requisição e não ficar esperando pela resposta para poder fazer outra? Também é possível criando novos processos (uma opção mais pesada) ou criando novas threads (mais leve que processos, mas ainda assim, não tão leve quanto corrotinas que veremos adiante). Todas essas coisas podem ser trabalhadas para se chegar no objetivo de atingir assincronismo.

No entanto, o modelo assíncrono do Swoole é focado em *nonblocking I/O* e *I/O multiplexing* que é mais popularmente conhecido como *event driven* (com eventos de leitura e escrita a partir do monitoramento de *descritores de arquivos*) e usa chamadas de sistema como *select*, *pool* ou *epool*. Além disso, o Swoole implementa corrotinas com o modelo *CSP* (Communicating sequential processes) que é bem conhecido na linguagem Go com `go`, `chan` e `defer`. Se você já trabalhou com concorrência em Go, terá muita facilidade para assimilar em como as coisas são feitas no Swoole.

**A arquitetura tradicional com PHP-FPM**

Na arquitetura tradicional da maior parte das aplicações escritas em PHP, temos um servidor web e um *process manager* baseado no protocolo [FastCGI](https://en.wikipedia.org/wiki/FastCGI), que no caso do PHP o oficial é o *PHP-FPM*. No lado do servidor web, o mais usado atualmente é o Nginx, que por sinal, também usa o padrão Reactor com *I/O multiplexing (epool)* para conseguir responder a milhares de conexões simultâneas, diferentemente do *Apache* (outro popular servidor) que implementa um modelo híbrido *multi-process* e *multi-thread* (quando usando Worker MPM em detrimento ao Prefork MPM).

É relativamente comum ler que o *PHP-FPM* é *multi-thread*, mas na realidade ele é *multi-process*. As requisições são iniciadas pelo servidor web (Nginx, por exemplo) que as redireciona para o *PHP-FPM* via o protocolo binário *FastCGI*. O *Master Process* do *PHP-FPM* recebe essas requisições e as aloca em um novo *worker process*. O PHP-FPM gerencia *pools* de *worker processes*, cada *pool* pode gerenciar um determinado número de processos filhos (*worker processes*) para lidar com as requisições (e esse número depende das configurações do PHP-FPM e da quantidade de memória disponível). Todo esse processo é bloqueante por natureza, ou seja, enquanto o script estiver sendo executado (acessando I/O, por exemplo). Só no final quando a resposta é processada e retornada que o processo filho criado pelo *PHP-FPM* é reciclado.

*Uma nota sobre pools:* A ideia de uma *pool* é pré-alocar uma determinada quantidade de processos ou threads (no caso de uma Thread Pool) para que fiquem em espera para realizarem alguma tarefa em um tempo futuro. É uma forma de evitar desperdício de tempo com a alocação de um novo processo ou thread, que não é uma operação muito leve no nível do kernel. Além disso, é uma forma de determinar recursos finitos para o número de clientes que se espera ter. Por exemplo, se o servidor tem 8GB de memória, mas só podemos usar 6GB para as pools que receberão as requisições, então as configuramos para consumirem no máximo isso, o que vai limitar o número de processos / threads que elas poderão pré-alocar.

Em um cenário onde há necessidade de alta concorrência para responder à milhares ou dezenas de milhares de conexões, todo esse processo tradicional é muito custoso (gasta-se muito tempo com [troca de contexto](https://pt.wikipedia.org/wiki/Troca_de_contexto)), muita alocação de memória e a concorrência fica limitada à quantidade de processos que sua máquina consegue manejar. Não obstante, é lento, pois a cada nova requisição todo o código precisa ser inicializado do zero novamente. Mas esse modelo tradicional também tem seus benefícios, a depender do ponto de vista. Por exemplo, é um modelo *stateless*, o tempo de vida de uma requisição é curto, assim que o resultado é preparado e retornado, tudo é finalizado e retirado da memória, isso diminui as chances de *memory leaks*.

Abaixo o diagrama de como funciona essa arquitetura tradicional. O Nginx recebe as requisições da Web (normalmente advindas das portas 80 e 443) e então as encaminha para o socket FastCGI do *PHP-FPM* que maneja as execuções nas *pools* de *worker processes.*

![Diagrama arquitetura tradicional](https://dkrn4sk0rn31v.cloudfront.net/2019/11/12110319/nginx-php-fpm.png)

O fluxo tradicional com *PHP-FPM* é mais ou menos assim:

- Recebe a requisição;
- Carrega os códigos (processo léxico, de parser, compilação para *opcodes* etc);
- Inicializa os objetos e variáveis;
- Executa o código;
- Retorna a resposta;
- Recicla os recursos, liberando o *worker process* para outra requisição;

Para a maioria das aplicações de uso menos intensivo de I/O, esse modelo é perfeito e estável. Mas quando precisamos de um uso mais intensivo como, por exemplo, para lidar com milhares ou centenas de milhares de conexões simultâneas, é impossível que tenhamos centenas de milhares de processos sendo criados para cuidar dessas requisições. Muito menos poderíamos criar centenas de milhares de threads, dada a limitação do número de threads por processo imposta pelo sistema operacional e também devido ao *overhead* que isso causaria. Mesmo que fosse possível resolver o problema usando um número menor de threads, trabalhar com threads não é simples, impõe muitos problemas de comunicação e sincronia para lidar.

É nesse ponto que entram as soluções de I/O não bloqueante com multiplexing de I/O. É aqui que ReactPHP, Nginx, NodeJS, Netty, Swoole, Go etc, resolvem o problema, cada um na sua maneira. Mas a forma mais comum e mais utilizada é usando uma abordagem orientada a eventos com o padrão Reactor.

O ciclo de vida de uma requisição em um servidor do Swoole se limita a bem menos etapas, pois depois do *first load*, ele mantém os recursos em memória:

- Recebe a requisição;
- Executa o código;
- Retorna a resposta;

**A arquitetura com Swoole**

Em um cenário de alta concorrência e em um modelo de I/O não bloqueante como é o caso do Swoole, ele deixa de lidar apenas com uma requisição bloqueante (como funciona no *PHP-FPM*) e ganha o poder de lidar com várias requisições ao mesmo tempo, de forma não bloqueante, graças aos reactors.

O Swoole roda em modo CLI e ele forka um determinado número de processos a depender da quantidade de núcleos da sua CPU. Veja um panorama da arquitetura do Swoole:

![Camadas arquitetura com Swoole](https://dkrn4sk0rn31v.cloudfront.net/2019/11/12095134/swoole.png)

O padrão Reactor no Swoole é *multi-thread* e assíncrono, igual comentamos anteriormente, ele faz uso da chamada de sistema *epool*. O Main Reactor é uma thread, assim como os reactors auxiliares. O Main Reactor é o que fica ouvindo o socket por novas conexões, ele faz balanceamento de carga entre os reactors auxiliares.

- **Master:** o processo principal, o processo pai, o que forkará o processo **Manager** e que criará as threads do Reactor.
- **Manager:** processo gerenciador, o que forka e gerencia os processos workers. Os reactors estarão em constante comunicação com o Manager (através do processo Master).
- **Worker:** processo de trabalho, onde as tarefas são executadas;
- **Task Worker:** processo de trabalho de tarefa assíncrona, é um auxiliador do Worker, ele trabalha principalmente processando tarefas de sincronização de longa data;

O mais importante aqui é entendermos que quando iniciamos um servidor do Swoole, **2 + n +** **m** processos são criados, ou seja, o processo **Master**, o processo **Manager** e **n** refere-se aos processos **Workers** e **m** refere-se aos processos **Task Workers**, sendo que **n** e **m** serão relativos à quantidade de núcleos do seu processador. Se o seu processador tiver 6 núcleos, ele forkará 8 processos, sendo 3 Workers e 3 Task Workers.

A árvore de processo da execução de um servidor do Swoole em uma máquina de 6 núcleos:

```
 | |   \-+= 05535 kennedytedesco php server.php (Master)
 | |     \-+- 05536 kennedytedesco php server.php (Manager)
 | |       |--- 05537 kennedytedesco php server.php (worker / task worker)
 | |       |--- 05538 kennedytedesco php server.php (worker / task worker)
 | |       |--- 05539 kennedytedesco php server.php (worker / task worker)
 | |       |--- 05540 kennedytedesco php server.php (worker / task worker)
 | |       |--- 05541 kennedytedesco php server.php (worker / task worker)
 | |       \--- 05542 kennedytedesco php server.php (worker / task worker)

```

Quando trabalhamos de forma assíncrona não sabemos em qual tempo futuro a nossa resposta estará pronta e então passamos a usar os famosos *callbacks*. Com o tempo, é comum termos muitos *callbacks* aninhados, é aí que chegamos no famoso [Callback Hell](http://callbackhell.com/). Por exemplo, em NodeJS:

```js
fs.readdir(source, function (err, files) {
  if (err) {
    console.log('Error finding files: ' + err)
  } else {
    files.forEach(function (filename, fileIndex) {
      console.log(filename)
      gm(source + filename).size(function (err, values) {
        if (err) {
          console.log('Error identifying file size: ' + err)
        } else {
          console.log(filename + ' : ' + values)
          aspect = (values.width / values.height)
          widths.forEach(function (width, widthIndex) {
            height = Math.round(width / aspect)
            console.log('resizing ' + filename + 'to ' + height + 'x' + height)
            this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
              if (err) console.log('Error writing file: ' + err)
            })
          }.bind(this))
        }
      })
    })
  }
})

```

Existem várias formas que diferentes linguagens/frameworks usam para resolver esse problema, como: Promises (recomendo a leitura do artigo de [Promises no ReactPHP](https://www.treinaweb.com.br/blog/promises-no-reactphp/)) , yield/generators, instruções Async / Await (como em C#).

Em Swoole a forma mais elegante e eficiente de resolver esse problema é usando corrotinas. Corrotinas são uma importante parte do núcleo do Swoole.

Um pouco da sintaxe de corrotinas:

```php
