Amphp之事件循环
Posted Flybeta
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Amphp之事件循环相关的知识,希望对你有一定的参考价值。
目录
事件循环(Event Loop)
人们可能会惊讶地发现 php 标准库已经拥有我们编写事件驱动和非阻塞应用程序所需的一切。只有当我们要求它同时轮询数千个文件描述符以进行 IO 活动时,我们才会在这方面达到原生 PHP 功能的限制。但是,即使在这种情况下,问题也不在于 PHP,而在于底层系统select()
调用,随着负载的增加,它的性能下降是线性的。
对于扩展到大容量的性能,我们需要目前仅在扩展中才能找到的更高级的功能。例如,如果您希望在支持 Amp 的套接字服务器中同时为 10,000 个客户端提供服务,您应该使用基于 PHP 扩展的事件循环实现之一。但是,如果您在严格的本地程序中使用 Amp 以实现非阻塞并发,或者您不需要在服务器应用程序中同时处理数百个客户端,则原生 PHP 功能应该足够了。
全局访问器(Global Accessor)
Amp 对事件循环使用全局访问器,因为每个应用程序只有一个事件循环。同时运行两个循环是没有意义的,因为它们只需要以繁忙的等待方式相互调度才能正确运行。
应该通过 Amp\\Loop
提供的方法访问事件循环。首次使用访问器时,Amp 将自动设置可用的最佳驱动程序,请参阅下一节。
Amp\\Loop::set()
可用于设置自定义驱动程序或在测试中重置驱动程序,因为每个测试都应使用新的驱动程序实例运行以实现测试隔离。对于 PHPUnit,您可以使用TestListener 在每次测试后自动重置事件循环。
实现(Implementations)
Amp 基于各种后端提供不同的事件循环实现。所有实现都扩展了 Amp\\Loop\\Driver
。从外部 API 的角度来看,它们的行为方式完全相同。主要区别与潜在的性能特征有关。当前的实现在这里列出:
Class | Extension | Repository |
---|---|---|
Amp\\Loop\\NativeDriver | - | - |
Amp\\Loop\\EvDriver | pecl/ev | pecl-ev |
Amp\\Loop\\EventDriver | pecl/event | pecl-event |
Amp\\Loop\\UvDriver | pecl/uv | pecl-uv |
为您的应用程序选择哪一种实现并不重要。 Amp 将自动选择可用的最佳驱动程序。在本地依赖 NativeDriver
进行开发的同时,在生产中拥有其中一个扩展是非常好的。
如果您想在开发过程中快速切换实现,例如为了比较或测试,您可以将 AMP_LOOP_DRIVER
环境变量设置为其中一个类。如果您使用自定义实现,这仅在实现不带任何参数时才有效。
事件循环作为任务调度器(Event Loop as Task Scheduler)
为了有效地使用事件循环进行编程,我们首先需要了解的是:
The event loop is our task scheduler.
只要它运行,事件循环就控制程序流程。一旦我们告诉事件循环运行,它将保持控制,直到应用程序出错、无事可做或被明确停止。
思考这个非常简单的例子:
<?php
require "vendor/autoload.php";
use Amp\\Loop;
function tick()
echo "tick\\n";
echo "-- before Loop::run()\\n";
Loop::run(function()
Loop::repeat($msInterval = 1000, "tick");
Loop::delay($msDelay = 5000, "Amp\\\\Loop::stop");
);
echo "-- after Loop::run()\\n";
执行上述示例后,您应该会看到如下输出:
-- before Loop::run()
tick
tick
tick
tick
-- after Loop::run()
这个输出表明事件循环的运行循环内部发生的事情就像它自己的独立程序一样。除非没有更多计划事件或调用 Loop::stop()
,否则您的脚本将不会继续超过 Loop::run()
点。
虽然应用程序可以并且经常确实完全在运行循环的范围内发生,但我们也可以使用事件循环来执行以下示例,该示例为交互式控制台输入强加了一个短暂的超时:
<?php
use Amp\\Loop;
$myText = null;
function onInput($watcherId, $stream)
global $myText;
$myText = fgets($stream);
stream_set_blocking(STDIN, true);
Loop::cancel($watcherId);
Loop::stop();
Loop::run(function ()
echo "Please input some text: ";
stream_set_blocking(STDIN, false);
// Watch STDIN for input
Loop::onReadable(STDIN, "onInput");
// Impose a 5-second timeout if nothing is input
Loop::delay($msDelay = 5000, "Amp\\\\Loop::stop");
);
var_dump($myText); // whatever you input on the CLI
// Continue doing regular synchronous things here.
显然,在这个例子中我们可以简单地同步使用 fgets(STDIN)
。我们只是展示了可以根据需要进出事件循环以混合同步任务和非阻塞任务。
让我们继续学习事件循环 API。
以上是关于Amphp之事件循环的主要内容,如果未能解决你的问题,请参考以下文章