fiasco/async

使用pcntl运行异步运行时PHP子进程的PHP库。

4.1-beta3 2023-10-12 00:58 UTC

README

用于异步执行任务的PHP库。

此库允许您通过PCNTL扩展使用子进程并行执行匿名函数。

匿名函数的返回值将被序列化并返回给父进程以进行处理。

注意:不支持序列化对象作为返回值。

注意:由于异常对象可能包含无法序列化的对象,因此不建议将它们用作onSuccess回调函数的返回值。

如果您想运行异步活动,如文件操作或服务器交互,请考虑使用ReactPHP(此库依赖于ReactPHP)。

安装

推荐使用composer进行安装。

composer require fiasco/async:^3.0

使用方法

请参阅示例

使用分叉管理器创建并行执行的分叉。

<?php
use Async\ForkManager;
use Async\ForkInterface;
use Async\Exception\ChildExceptionDetected;

$forkManager = new ForkManager();

// Return an instance of ForkInterface.
// Will be either a SynchronousFork or an AsynchronousFork if PCNTL extension
// is enabled.
$fork = $forkManager->create();

// This anonymous function will run inside a child fork.
$fork->run(function (ForkInterface $fork) {
  return file_get_contents('https://google.com/');
});

// Return  contents from run function will be provided as the input argument
// to the onSuccess callback. This anonymous function is run in the parent thread.
$fork->onSuccess(function ($html) {
  echo "Got website with a length of ".strlen($html)." bytes\n";
});

// On error is called when the child process encounters an uncaught throwable.
$fork->onError(function (ChildExceptionDetected $e) {
  echo "ERROR: ".$e->getMessage().PHP_EOL;
});

// Block on main thread until all forks have completed.
$forkManager->awaitForks();

您还可以将调用链在一起

<?php
use Async\ForkManager;
use Async\ForkInterface;
use Async\Exception\ChildExceptionDetected;

$forkManager = new ForkManager();

$forkManager->create()
->run(function (ForkInterface $fork) {
  return file_get_contents('https://google.com/');
})
->onSuccess(function ($html) {
  echo "Got website with a length of ".strlen($html)." bytes\n";
})
->onError(function (ChildExceptionDetected $e) {
  echo "ERROR: ".$e->getMessage().PHP_EOL;
});

// Block on main thread until all forks have completed.
$forkManager->awaitForks();

如果您喜欢在foreach循环中使用结果,可以使用ForkManager->getForkResults()返回结果。要包含错误,请将true作为函数的第一个参数传递。

<?php
use Async\ForkManager;

$forkManager = new ForkManager();
// Wait up to 3 seconds for fork response before giving up.
$forkManager->setWaitTimeout(3);

// This will result in a caught fatal error from the child.
$forkManager->create()->run(fn() => @$foo->doNothing());

// This fork will catch a thrown exception and trigger the onError callback
// in the parent thread.
$forkManager->create()->run(function (ForkInterface $fork) {
  // You can set labels inside the fork to give better information about
  // what the specific fork is doing.
  $fork->setLabel("Fork that throws an error.");
  throw new \Exception('bar');
});

// Waiting for the fork in parent will timeout and force the fork
// to error out. The Fork child will still attempt to return the
// result but it will fail.
$forkManager->create()->run(function (ForkInterface $fork) {
  $fork->setLabel("Fork that will timeout.");
  sleep(4);
  return 'fuz';
});

$forkManager->create()->run(fn() => 'baz');

$forkManager->awaitForks();

// Loop over errored forks.
foreach ($forkManager->getForks(ForkInterface::STATUS_ERROR) as $fork) {
  // Result will be instance Async\Exception\ChildExceptionDetected.
  echo sprintf("Fork '%s' encountered an error:\n", $fork->getLabel());
  // echo $fork->getResult()->getMessage() . PHP_EOL;
}

foreach ($forkManager->getForks(ForkInterface::STATUS_COMPLETE) as $fork) {
  // Result will be instance Async\Exception\ChildExceptionDetected.
  echo sprintf("Fork '%s' completed.\n", $fork->getLabel());
  // echo $fork->getResult()->getMessage() . PHP_EOL;
}

作为onError回调的替代方案,您还可以使用getForks()方法获取所有出错的分叉。

<?php

use Async\ForkInterface;

// .. create forks.

// Wait for all forks to complete.
$forkManager->awaitForks();

// Loop over errored forks.
foreach ($forkManager->getForks(ForkInterface::STATUS_ERROR) as $fork) {
  // Result will be instance Async\Exception\ChildExceptionDetected.
  echo sprintf("Fork '%s' encountered an error:\n", $fork->getLabel());
  echo $fork->getResult()->getMessage() . PHP_EOL;
}