Processamento paralelo com PHP: por que, como e quando

Back-end Ferramentas PHP Tutoriais Webdev
Processamento paralelo com PHP: por que, como e quando

Quando pensamos em PHP, normalmente imaginamos um código síncrono, de thread única, que lida com uma tarefa por vez.

Mas o PHP é mais versátil do que costuma ser considerado. Graças ao suporte ao controle de processos (pcntl), o PHP consegue gerenciar o paralelismo por meio de bifurcação de processos, um conceito nativo de sistemas operacionais do tipo Unix.

Como o suporte ao controle de processos é comum em sistemas UNIX, ele também é compatível com sistemas operacionais semelhantes ao Unix, como Linux e macOS.

O que é multiprocessamento e por que você deve se importar?

O multiprocessamento permite executar múltiplas operações simultaneamente. Isso é especialmente útil quando:

  • Você está executando tarefas que exigem muita CPU e que podem ser paralelizadas.
  • Você precisa lidar com vários trabalhos em segundo plano em paralelo.
  • Você deseja reduzir o tempo de execução dividindo uma tarefa entre vários processos.
  • Você está escrevendo scripts PHP de linha de comando onde desempenho e capacidade de resposta são importantes.

Ao escrever scripts CLI (como uma ferramenta de linha de comando), especialmente para tarefas em segundo plano, daemons ou workers, usar pcntl_fork() é uma técnica poderosa.

Introdução pcntl_fork() : criando processos paralelos em PHP

A pcntl_fork() função permite que seu script PHP clone a si mesmo, criando um processo filho que roda em paralelo ao pai. Essa técnica vem diretamente do mundo Unix e abre as portas para o multiprocessamento real em PHP.

Aqui está um exemplo simples que demonstra o uso básico de pcntl_fork() :

  // Fork the process $pid = pcntl_fork();  if ($pid == -1) { // Fork failed exit("Could not fork process.\n"); } elseif ($pid > 0) { // Parent process echo ' Parent process. PID: ' . getmypid() . "\n"; echo " Created child with PID: $pid\n";  } else { // Child process echo '  Child process. PID: ' . getmypid() . "\n"; sleep(1); // Simulate work echo "  Child process done.\n"; exit(0); }  // Wait for child to exit pcntl_waitpid($pid, $status); echo " Child {$pid} has finished with status {$status}.\n"; if (pcntl_wifexited($status)) { echo " The child status code represents a normal exit.\n"; echo ' The child returned the code: ' . pcntl_wexitstatus($status) . "\n"; } if (pcntl_wifsignaled($status)) { echo " The child status exit because a siginal.\n"; echo ' The child was terminated by signal code: ' . pcntl_wtermsig($status) . "\n"; }  

O que está acontecendo aqui?

  • O script se bifurca.
  • Os processos pai e filho continuam sendo executados de forma independente.
  • O processo filho executa sua lógica e sai.
  • O processo pai aguarda o término do processo filho e analisa o status de saída.

Este exemplo oferece controle total e visibilidade sobre como um processo filho se comporta e como o pai pode monitorá-lo ou gerenciá-lo.

Explicação passo a passo

$pid = pcntl_fork(); 

A pcntl_fork() função diz ao sistema operacional: "Crie um clone meu para trabalhar em paralelo".

Após o pctnl_fork , dois processos executam o mesmo código. Um processo é o processo pai e o segundo é o processo filho.

Se pcntl_fork retornar:

  • -1 , o clone falhou.
  • 0 , você está dentro do processo filho.
  • Um PID positivo significa que você ainda é o pai ou a mãe e acabou de obter a identidade da criança.

if ($pid == -1) { exit("Could not fork process.\n"); } 

A operação de bifurcação falhou. O processo é encerrado antecipadamente.


elseif ($pid > 0) { echo ' Parent process. PID: ' . getmypid() . "\n"; echo " Created child with PID: $pid\n"; } 

Você é o processo pai.
Você imprime seu próprio PID e o ID do novo filho (retornado pela função fork).


else { echo '  Child process. PID: ' . getmypid() . "\n"; sleep(1); // Simulate work echo "  Child process done.\n"; exit(0); } 

Você é o processo filho!
Esta parte é executada apenas pelo processo filho.
O processo filho dorme por 1 segundo (como se estivesse executando uma tarefa específica), imprime mensagens e depois sai.

exit(0) é importante. Garante que o filho não execute acidentalmente código destinado apenas ao pai.


pcntl_waitpid($pid, $status); 

O processo pai aguarda a conclusão do processo filho.
Esta linha informa ao processo pai para pausar e aguardar até que o processo filho específico (por $pid ) seja concluído.


echo " Child {$pid} has finished with status {$status}.\n"; 

Assim que o processo filho termina, o processo pai é notificado com um código de status. Precisamos inspecionar o código de status para entender por que o processo filho encerrou a execução (por exemplo, se concluiu a tarefa corretamente, saiu com erro ou foi interrompido por um sinal do sistema operacional).


if (pcntl_wifexited($status)) { echo " The child status code represents a normal exit.\n"; echo ' The child returned the code: ' . pcntl_wexitstatus($status) . "\n"; } 

Verificamos se a criança saiu normalmente.
Em caso positivo, imprimimos o código de retorno ( 0 se a criança concluiu com sucesso).


if (pcntl_wifsignaled($status)) { echo " The child status exit because a signal.\n"; echo ' The child was terminated by signal code: ' . pcntl_wtermsig($status) . "\n"; } 

Ou talvez a criança tenha sido interrompida.
Isso acontece se um sinal interrompeu o processo (por exemplo, SIGKILL , SIGTERM ).

Resumo do código

Papel Bloco de código Descrição
Pais $pid > 0 O pai cria e supervisiona a execução da tarefa.
Criança $pid == 0 O processo filho executa a tarefa e sai.
Espere pcntl_waitpid() O processo pai aguarda a conclusão do processo filho.
Verificação de status pcntl_wifexited() , pcntl_wifsignaled() O processo pai verifica se o processo filho foi concluído corretamente.

Quando e por que usar forking em PHP

Você pode usar pcntl_fork() scripts CLI quando:

  • Você deseja executar várias tarefas ao mesmo tempo, como baixar arquivos, processar filas ou executar trabalhos em segundo plano.
  • Você está escrevendo um daemon ou sistema de trabalho que precisa escalar e gerenciar tarefas paralelas de forma eficiente.
  • Você quer reduzir o tempo de espera realizando tarefas independentes simultaneamente.