Introdução à concorrência e multithreading em PHP
Tradicionalmente, o PHP é considerado uma linguagem síncrona e single-thread. No entanto, aplicações web modernas exigem o processamento de múltiplas tarefas simultaneamente: upload de arquivos, trabalho com APIs, processamento de filas. A concorrência e o multithreading em PHP permitem resolver essas tarefas, acelerando a execução de scripts e aumentando a capacidade de resposta das aplicações.
Neste artigo, abordaremos os conceitos-chave: desde os princípios básicos de concorrência até a aplicação prática das extensões pthreads e parallel. Você aprenderá como organizar a execução paralela de tarefas, evitar condições de corrida e melhorar o desempenho do seu código PHP.
Conceitos fundamentais de concorrência e multithreading
Síncrono vs Assíncrono
No modelo síncrono, o PHP executa o código estritamente de forma sequencial. Se um script faz uma requisição HTTP, a execução é interrompida até receber a resposta. A assincronia permite iniciar tarefas sem esperar sua conclusão.
Exemplo de código síncrono:
<?php$result1 = file_get_contents('https://api.example.com/data1');$result2 = file_get_contents('https://api.example.com/data2');// Ambas as requisições são executadas sequencialmente?>Threads e Processos
- Processo — uma cópia isolada do programa com seu próprio espaço de endereçamento.
- Thread — uma unidade de execução leve dentro de um processo, compartilhando memória.
Em PHP, o multithreading é implementado através de threads. Para trabalhar com elas, são necessárias extensões especiais, pois a compilação padrão do PHP não suporta threads.
Condição de corrida e sincronização
Ao trabalhar com múltiplas threads em dados compartilhados, pode ocorrer uma condição de corrida (race condition). Para preveni-la, são usados mutexes, bloqueios e operações atômicas.
Ferramentas para multithreading em PHP
Extensão pthreads
pthreads — uma das primeiras extensões para trabalhar com threads. Ela fornece as classes Thread, Worker e Pool. Importante: a extensão funciona apenas no modo CLI e requer uma compilação PHP com ZTS (Zend Thread Safety).
Exemplo de uma thread simples:
<?phpclass MyThread extends Thread { public function run() { echo "Thread iniciada"; }}$thread = new MyThread();$thread->start();$thread->join();?>Extensão parallel
parallel — uma extensão mais moderna, introduzida no PHP 7.4. É mais conveniente e segura. Funciona através de canais (channels) para transferência de dados entre threads.
Exemplo com parallel:
<?php$runtime = new \\parallel\\Runtime();$future = $runtime->run(function(){ return "Olá da thread paralela!";});echo $future->value(); // Obtém o resultado?>Assincronia com ReactPHP e Amp
Se você não precisa de multithreading real, mas requer concorrência, utilize bibliotecas de I/O assíncrono:
- ReactPHP — biblioteca orientada a eventos com event loop.
- Amp — async/await para PHP, semelhante ao JavaScript.
Exemplos práticos e melhores práticas
Exemplo: Processamento paralelo de URLs
Suponha que você precise verificar a disponibilidade de 10 sites. Sincronamente, isso levaria muito tempo. Use parallel para acelerar:
<?php$urls = [ 'https://google.com', 'https://yandex.ru', 'https://github.com'];
$runtimes = [];$futures = [];
foreach ($urls as $url) { $runtime = new \\parallel\\Runtime(); $runtimes[] = $runtime; $futures[] = $runtime->run(function($url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 5);