Esta biblioteca fornece um wrapper pequeno e fácil para a extensão PCNTL do PHP. Permite a execução de diversos processos em paralelo, com uma API fácil de usar.
Investimos muitos recursos na criação dos melhores pacotes de código aberto. Você pode nos apoiar comprando um de nossos produtos pagos.
Agradecemos muito que você nos envie um cartão postal de sua cidade natal, mencionando qual(is) de nossos pacotes você está usando. Você encontrará nosso endereço em nossa página de contato. Publicamos todos os cartões postais recebidos em nosso mural virtual de cartões postais.
Você pode instalar o pacote via compositor:
composer require spatie/async
use Spatie Async Pool ;
$ pool = Pool:: create ();
foreach ( $ things as $ thing ) {
$ pool -> add ( function () use ( $ thing ) {
/ / Do a thing
})-> then ( function ( $ output ) {
/ / Handle success
})-> catch ( function ( Throwable $ exception ) {
/ / Handle exception
});
}
$ pool -> wait ();
Ao criar processos assíncronos, você receberá uma instância de ParallelProcess
retornada. Você pode adicionar os seguintes ganchos de eventos em um processo.
$ pool
-> add ( function () {
/ / ...
})
-> then ( function ( $ output ) {
/ / On success , `$output` is returned by the process or callable you passed to the queue .
})
-> catch ( function ( $ exception ) {
/ / When an exception is thrown from within a process , it 's caught and passed here.
})
-> timeout ( function () {
/ / A process took too long to finish.
})
;
Em vez de usar métodos no objeto $pool
, você também pode usar as funções auxiliares async
e await
.
use Spatie Async Pool ;
$ pool = Pool:: create ();
foreach ( range ( 1 , 5 ) as $ i ) {
$ pool [] = async ( function () {
usleep ( random_int ( 10 , 1000 ));
return 2 ;
})-> then ( function ( int $ output ) {
$ this -> counter += $ output ;
});
}
await ( $ pool );
Se uma Exception
ou Error
for lançado de dentro de um processo filho, ele poderá ser capturado por processo especificando um retorno de chamada no método ->catch()
.
$ pool
-> add ( function () {
/ / ...
})
-> catch ( function ( $ exception ) {
/ / Handle the thrown exception for this child process.
})
;
Se não houver nenhum manipulador de erros adicionado, o erro será lançado no processo pai ao chamar await()
ou $pool->wait()
.
Se o processo filho parar inesperadamente sem lançar um Throwable
, a saída gravada em stderr
será agrupada e lançada como SpatieAsyncParallelError
no processo pai.
Ao digitar dicas nas funções catch
, você pode fornecer vários manipuladores de erros, cada um para tipos individuais de erros.
$ pool
-> add ( function () {
throw new MyException ( ' test ' );
})
-> catch ( function ( MyException $ e ) {
/ / Handle `MyException`
})
-> catch ( function ( OtherException $ e ) {
/ / Handle `OtherException`
});
Observe que assim que uma exceção for tratada, ela não acionará nenhum outro manipulador
$ pool
-> add ( function () {
throw new MyException ( ' test ' );
})
-> catch ( function ( MyException $ e ) {
/ / This one is triggerd when `MyException` is thrown
})
-> catch ( function ( Exception $ e ) {
/ / This one is not triggerd , even though `M yException ` extends `E xception `
});
Se você precisar interromper um pool antecipadamente, porque a tarefa que ele estava executando foi concluída por um dos processos filhos, você pode usar o método $pool->stop()
. Isto impedirá que o pool inicie quaisquer processos adicionais.
use Spatie Async Pool ;
$ pool = Pool:: create ();
/ / Generate 10 k processes generating random numbers
for ( $ i = 0 ; $ i < 10000 ; $ i ++) {
$ pool -> add ( function () use ( $ i ) {
return rand ( 0 , 100 );
})-> then ( function ( $ output ) use ( $ pool ) {
/ / If one of them randomly picks 100 , end the pool early .
if ( $ output === 100 ) {
$ pool -> stop ();
}
});
}
$ pool -> wait ();
Observe que um pool se tornará inútil após ser interrompido e um novo pool deverá ser criado, se necessário.
Por padrão, o pool usará php
para executar seus processos filhos. Você pode configurar outro binário assim:
Pool:: create ()
-> withBinary ( ' /path/to/php ' );
Além de usar encerramentos, você também pode trabalhar com Task
. Uma Task
é útil em situações em que você precisa de mais trabalho de configuração no processo filho. Como um processo filho é sempre inicializado do nada, é provável que você queira inicializar, por exemplo. o contêiner de dependência antes de executar a tarefa. A classe Task
torna isso mais fácil de fazer.
use Spatie Async Task ;
class MyTask extends Task
{
public function configure ()
{
/ / Setup eg . dependency container , load config , ...
}
public function run ()
{
/ / Do the real work here.
}
}
/ / Add the task to the pool
$ pool -> add ( new MyTask ());
Se você deseja encapsular a lógica da sua tarefa, mas não deseja criar um objeto Task
completo, você também pode passar um objeto invocável para o Pool
.
class InvokableClass
{
/ / ...
public function __invoke ()
{
/ / ...
}
}
$ pool -> add ( new InvokableClass ( / * ... * / ));
Você é livre para criar quantos pools quiser, cada pool tem sua própria fila de processos que irá manipular.
Um pool é configurável pelo desenvolvedor:
use Spatie Async Pool ;
$ pool = Pool:: create ()
/ / The maximum amount of processes which can run simultaneously.
-> concurrency ( 20 )
/ / The maximum amount of time a process may take to finish in seconds
/ / ( decimal places are supported for more granular timeouts ) .
-> timeout ( 15 )
/ / Configure which autoloader sub processes should use.
-> autoload ( __DIR__ . ' /../../vendor/autoload.php ' )
/ / Configure how long the loop should sleep before re - checking the process statuses in microseconds .
-> sleepTime ( 50000 )
;
Se as extensões necessárias ( pcntl
e posix
) não estiverem instaladas em seu tempo de execução PHP atual, o Pool
retornará automaticamente para a execução síncrona de tarefas.
A classe Pool
possui um método estático isSupported
que você pode chamar para verificar se sua plataforma é capaz de executar processos assíncronos.
Se você estiver usando uma Task
para executar processos, somente o método run
dessas tarefas será chamado durante a execução no modo síncrono.
Ao usar este pacote, você provavelmente está se perguntando o que está acontecendo por baixo da superfície.
Estamos usando o componente symfony/process
para criar e gerenciar processos filhos em PHP. Ao criar processos filhos dinamicamente, podemos executar scripts PHP em paralelo. Esse paralelismo pode melhorar significativamente o desempenho ao lidar com múltiplas tarefas síncronas, que na verdade não precisam esperar umas pelas outras. Ao fornecer a essas tarefas um processo separado para execução, o sistema operacional subjacente pode cuidar de executá-las em paralelo.
Há uma ressalva ao gerar processos dinamicamente: você precisa ter certeza de que não haverá muitos processos ao mesmo tempo, ou o aplicativo poderá travar. A classe Pool
fornecida por este pacote se encarrega de lidar com quantos processos você desejar, agendando-os e executando-os quando for possível.
Essa é a parte que async()
ou $pool->add()
faz. Agora vamos ver o que await()
ou $pool->wait()
faz.
Quando vários processos são gerados, cada um pode ter um tempo separado para conclusão. Um processo pode, por exemplo. tem que esperar por uma chamada HTTP, enquanto o outro tem que processar grandes quantidades de dados. Às vezes você também tem pontos em seu código que precisam esperar até que o resultado de um processo seja retornado.
É por isso que temos que esperar em um determinado momento: para que todos os processos em um pool terminem, para que possamos ter certeza de que é seguro continuar sem matar acidentalmente os processos filhos que ainda não foram concluídos.
A espera por todos os processos é feita por meio de um loop while
, que aguardará até que todos os processos sejam finalizados. A determinação de quando um processo é concluído é feita usando um ouvinte no sinal SIGCHLD
. Este sinal é emitido quando um processo filho é finalizado pelo kernel do sistema operacional. A partir do PHP 7.1, há um suporte muito melhor para escutar e manipular sinais, tornando esta abordagem mais eficiente do que, por exemplo. usando garfos ou soquetes de processo para comunicação. Você pode ler mais sobre isso aqui.
Quando um processo é concluído, seu evento de sucesso é acionado, ao qual você pode conectar-se com a função ->then()
. Da mesma forma, quando um processo falha ou expira, o loop atualizará o status desse processo e seguirá em frente. Quando todos os processos terminarem, o loop while verá que não há mais nada pelo que esperar e irá parar. Este é o momento em que seu processo pai pode continuar a ser executado.
Escrevemos uma postagem no blog contendo mais informações sobre casos de uso deste pacote, além de fazer comparações com outras bibliotecas PHP assíncronas, como ReactPHP e Amp: http://stitcher.io/blog/asynchronous-php.
composer test
Consulte CHANGELOG para obter mais informações sobre o que mudou recentemente.
Consulte CONTRIBUINDO para obter detalhes.
Se você encontrou um bug relacionado à segurança, envie um email para [email protected] em vez de usar o rastreador de problemas.
Você é livre para usar este pacote, mas se ele chegar ao seu ambiente de produção, agradecemos muito que você nos envie um cartão postal de sua cidade natal, mencionando quais de nossos pacotes você está usando.
Nosso endereço é: Spatie, Kruikstraat 22, 2018 Antuérpia, Bélgica.
Publicamos todos os cartões postais recebidos no site da nossa empresa.
A licença MIT (MIT). Consulte Arquivo de licença para obter mais informações.