Implementação simples de multithreading PHP

O multithreading no PHP está ausente " pronto para uso", então muitas opções foram inventadas para sua implementação, incluindo as extensões pthreads , AzaThread (CThread) e até mesmo alguns desenvolvimentos dos desenvolvedores do PHP.

A principal desvantagem para mim foram muitos "sinos e assobios" para essas soluções - nem sempre é necessário o intercâmbio de informações entre os threads e o processo pai ou a economia de recursos. Sempre deve haver a capacidade de resolver o problema de maneira rápida e econômica.

Quero fazer uma reserva com antecedência de que grandes segredos não abrem neste post - é mais provável para iniciantes no idioma, e decidi publicá-lo apenas porque eu mesmo havia enfrentado um problema e, não tendo encontrado uma solução pronta, fiz uma espécie de emulação de multithreading.

Portanto, a tarefa é processar uma grande quantidade de dados que entraram em nosso script. Minha tarefa era processar uma matriz JSON de informações textuais, digerindo que o script precisava coletar uma confirmação igualmente grande para o PostgreSQL.

Primeiro, coletamos os dados no arquivo pai:

index.php

// bigdata.json -    .      - ,     .. $big_json = file_get_contents('bigdata.json'); $items = json_decode($big_json, true); //   php    ,    , ,  unset($big_json); // ... 

O tamanho da matriz flutuou em torno de 400mb (mais tarde foi reduzido para ~ 50mb) e todas as informações foram textuais. Não é difícil estimar a velocidade com que tudo foi digerido, e como o script era executado no cron a cada 15 minutos, e o poder da computação era mais ou menos - o desempenho sofreu muito.

Após receber os dados, você pode estimar o volume e, se necessário, calcular o número necessário de threads para cada núcleo da CPU ou simplesmente decidir que haverá 4 threads e calcular o número de linhas para cada thread:

index.php

  // ... $threads = 4; $strs_per_thread = ceil(count($items) / $threads); //      -   echo "Items: ".count($items)."\n"; echo "Items per thread: ".$strs_per_thread."\n"; echo "Threads: ".$threads."\n"; // ... 

Vale a pena mencionar imediatamente - esse cálculo inicial não fornecerá um resultado exato pelo número de elementos para cada fluxo. É mais provável que seja necessário simplificar os cálculos.

E agora a própria essência - criamos tarefas para cada thread e as executamos. Faremos isso "testa" - criando uma tarefa para o segundo arquivo - thread.php. Ele atuará como um "fluxo", recebendo uma variedade de elementos para processar e iniciar independentemente do script principal:

index.php

  // ... for($i = 0; $i < $threads; $i++){ if($i == 0) { passthru("(php -f thread.php 0 ".$strs_per_thread." & ) >> /dev/null 2>&1"); } if($i == $threads-1) { passthru("(php -f thread.php ".($strs_per_thread * $i)." ".count($items)." & ) >> /dev/null 2>&1"); } if(($i !== 0)&&($i !== $threads-1)) { $start = $strs_per_thread * $i + 1; $end = $start -1 + $strs_per_thread; passthru("(php -f thread.php ".$start." ".$end." & ) >> /dev/null 2>&1"); } } // ... 

A função passthru () é usada para executar comandos do console, mas o script aguardará a conclusão de cada um deles. Para fazer isso, envolvemos o comando start em um conjunto de instruções que iniciará o processo e não retornará nada imediatamente, iniciando o processo e o processo pai não parará de esperar que cada filho execute:

 #  ,    ,   Linux- (php -f thread.php start stop & ) >> /dev/null 2>&1 

Infelizmente, não sei ao certo o que está acontecendo aqui - um conjunto de parâmetros me foi sugerido pelo meu familiar Linuxoid. Se você puder decifrar essa mágica nos comentários, ficarei grato e complementarei o post.

Arquivo thread.php:

 $start = $argv[1]; $stop = $argv[2]; for ($i = $start; $i <= $stop; $i++) { // -          } 

Dessa forma, bastante simples, você pode implementar emulação de multithreading em PHP.

Se reduzirmos todo o exemplo para secar a saída, acho que soaria assim: o encadeamento pai através da linha de comando lança processos filhos, dizendo a eles quais informações processar.

Quando digo "emulação", quero dizer que, com esse método de implementação, não há como trocar informações entre threads ou entre threads pai e filho. É adequado se souber previamente que esses recursos não são necessários.

Source: https://habr.com/ru/post/pt448464/


All Articles