这里有一个新的程序包,它称为spatie/async,旨在在PHP中进行异步并行处理。
对于许多Web开发人员而言,PHP中的并行处理似乎是一个边缘案例,但让我们看一下Spatie上的一些用例:
我们想创建一个易于使用的程序包,但是它可以解决我们的用例。上面列出的有些示例将不使用新spatie/async
软件包,因为Laravel还提供了一个队列系统。
这就是我们程序包中的异步代码的样子。
use Spatie\Async\Process;
$pool = Pool::create();
foreach (range(1, 5) as $i) {
$pool[] = async(function () use ($i) {
// Something to execute in a child process.
})->then(function (int $output) {
// Handle output returned from the child process.
})->catch(function (Exception $exception) {
// Handle exceptions thrown in the child process.
});
}
await($pool);
表现优于Amp?不完全
如果您使用并行PHP,则可能听说过Amp和ReactPHP。我们的软件包的目标是不与这两个软件包竞争,因为它仅解决了PHP并行化的一个微小方面。并尝试以其他方式解决它。
但是,我们确实运行了一些基准测试来比较我们的包与Amp的性能。特别感谢Amp的开发人员之一Niklas Keller。他指出了我们先前基准测试中的一些错误,并帮助使它们更加公平。
新的基准测试比较了一些方案。前两组绘制了一个空进程的执行时间,而第三组和第四组则使用几个sleep
时间间隔显示了具有不同完成时间的进程的执行时间。在这两组之间,我们还比较了有上限的并发配置和无上限的配置。上限意味着进程数量超过池一次执行的数量。
基准代码可以在这里找到。
比较Amp和Spatie/Async
我试图从这些测试中得出一些结论。
- 现实生活进程需要时间来运行和完成。对于我们的用例,“with logic”基准更为相关。
- 关于进程执行时间,似乎我们的程序包开销较小:只要池不必管理并发,我们的处理速度就会更快。
- 但是,在现实生活中的应用程序中,最大并发设置很有可能会生效,因此很明显,如果我们想要比Amp更好的性能,则需要改进代码库的这一部分。
什么ReactPHP?
我们已经将ReactPHP从基准测试中排除了,因为这不是一个公平的比较。ReactPHP不允许Tasks
像Amp和我们的包那样运行闭包或作为子过程。使用ReactPHP,您可以使用简单的流程,因此无法与之进行比较。
关于进程信号
我们的程序包和Amp之间最大的区别是进程之间的通信方式。我们仅依靠进程信号来确定进程何时完成。它可以减少开销,但也可以将Windows排除在目标平台之外。
UNIX系统中的进程可以相互发送信号。根据接收到的信号的种类,进程将有所不同。信号是由内核处理的,因此它们的电平很低。但是在PHP 7.1之前,您必须以declare(ticks=1)
可靠的方式使用异步信号。这意味着PHP将更频繁地检查信号,但同时也会带来很多开销:
tick是声明器中解析器执行的每N个低级tickable语句发生的事件。N的值是在声明块的指令部分中使用ticks = N来指定的。
使用PHP 7.1,有一种新方法可以处理内核发送的中断。
PHP 7.1中的Zend Engine扩展了安全超时和中断处理功能。实际上,PHP VM在每次循环迭代,用户函数进入或内部函数退出时检查EG(vm_interrupt)标志,并在必要时调用回调函数。
通过使用pcntl_async_signals(true)
,PHP现在将以更高效的方式检查信号。可以在Dmitry Stogov提交的rfc中找到更深入的解释。
正是由于这种机制,我们才能够以真正的异步方式对进程状态进行更改,而不必依赖套接字或进程状态轮询。
via https://stitcher.io/blog/asynchronous-php