A concorrência e o paralelismo são conceitos essenciais na programação moderna, permitindo que as aplicações realizem múltiplas tarefas simultaneamente, seja por meio da execução intercalada (concorrência) ou da execução simultânea (paralelismo). O PHP, conhecido principalmente por seu modelo de execução síncrona, evoluiu para suportar esses paradigmas por meio de várias técnicas.
Tradicionalmente, o PHP segue um modelo de execução síncrona, especialmente quando utilizado com o Apache em uma configuração típica de servidor web. Nesse modelo, cada requisição HTTP é tratada por um único processo PHP. As etapas envolvidas no processamento de uma requisição incluem:
Esse modelo garante simplicidade e facilidade de compreensão, mas pode se tornar ineficiente para tarefas que exigem execução paralela ou manipulação de múltiplas tarefas simultaneamente.
À medida que as aplicações web se tornaram mais complexas, a necessidade de execução concorrente e paralela no PHP cresceu. Vamos explorar as técnicas que o PHP oferece para alcançar esses paradigmas.
O código síncrono é a forma mais simples de execução, onde as tarefas são realizadas uma após a outra.
echo "Exemplo de Código Síncrono:\n";
function synchronousFunction() {
for ($i = 0; $i < 3; $i++) {
echo "Iteração do Loop Síncrono: $i\n";
sleep(1);
}
}
synchronousFunction();
Neste exemplo, cada iteração do loop é executada sequencialmente, com um atraso de um segundo entre as iterações. Essa abordagem é simples, mas ineficiente para tarefas que exigem muita E/S ou uso intensivo de CPU, que poderiam se beneficiar da execução paralela.
A criação de um processo (forking) gera um novo processo (filho) que é executado concorrentemente com o processo original (pai). Isso é útil para paralelizar tarefas.
echo "\nExemplo de Criação de Processo:\n";
function forkProcess() {
$pid = pcntl_fork();
if ($pid == -1) {
die('não foi possível criar o processo');
} else if ($pid) {
echo "Processo Pai: PID $pid\n";
pcntl_wait($status); // Proteger contra processos filhos zumbis
} else {
echo "Processo Filho: Olá a partir do processo filho!\n";
exit(0);
}
}
forkProcess();
Neste código, pcntl_fork() cria um processo filho. Os processos pai e filho são executados concorrentemente, permitindo a execução paralela de tarefas. O processo pai espera que o processo filho termine para evitar a criação de processos zumbis.
As capacidades de threads no PHP estão disponíveis por meio de extensões como pthreads. Os threads são mais leves que os processos e compartilham o mesmo espaço de memória, o que os torna adequados para tarefas que exigem dados compartilhados.
if (!class_exists('Thread')) {
die("Threads não são suportados nesta versão do PHP\n");
}
echo "\nExemplo de Threads:\n";
class MyThread extends Thread {
public function run() {
for ($i = 0; $i < 3; $i++) {
echo "Iteração do Loop do Thread: $i\n";
sleep(1);
}
}
}
$thread = new MyThread();
$thread->start();
$thread->join();
Este exemplo define uma classe MyThread que estende Thread. O método run é executado em um novo thread, funcionando concorrentemente com o thread principal. Essa abordagem é útil para operações dependentes de E/S, onde os threads podem lidar com a espera por recursos.
Os geradores fornecem uma maneira de implementar co-rotinas simples, permitindo que as funções retornem resultados de forma iterativa sem bloquear todo o programa.
echo "\nExemplo de Geradores:\n";
function simpleGenerator() {
yield 'Primeiro';
yield 'Segundo';
yield 'Terceiro';
}
$gen = simpleGenerator();
foreach ($gen as $value) {
echo "Gerador Retornou: $value\n";
}
Os geradores usam a palavra-chave yield para produzir valores um de cada vez, permitindo que a função seja pausada e retomada, facilitando uma forma de multitarefa cooperativa.
PHP percorreu um longo caminho desde suas raízes síncronas até suportar várias formas de concorrência e paralelismo. Embora o código síncrono continue sendo simples e eficaz para muitos casos de uso, técnicas como a criação de processos, o uso de threads e geradores abrem novas possibilidades para lidar com tarefas complexas e paralelizáveis de maneira eficiente.
Jorge García
Fullstack developer