Voltar à página principal
segunda-feira 30 setembro 2024
30

Concorrência e Paralelismo em PHP

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.

Modelo de Execução Padrão do PHP

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:

  • O Apache recebe uma requisição HTTP e a envia para o PHP.
  • O PHP executa o script do início ao fim em um único thread.
  • O PHP retorna a saída para o Apache, que então envia a resposta de volta para o cliente.

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.

Evolução da Concorrência e do Paralelismo no PHP

À 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.

1. Código Síncrono

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.

2. Criação de um Processo (Forking)

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.

3. Threads

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.

4. Geradores

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.

Tags:
php
Compartilhar:
Criado por:
Author photo

Jorge García

Fullstack developer