当前位置:首页 > 科技  > 软件

PHP 高性能的事件循环库 Revolt

来源: 责编: 时间:2024-02-01 12:44:44 326观看
导读Revolt是什么?Revolt是并发PHP应用程序的坚如磐石的事件循环。通常的PHP应用程序将大部分时间花在等待I/O上。虽然PHP是单线程的,但可以使用协作多任务来允许并发性,方法是使用等待时间来做不同的事情。PHP的传统同步执

Revolt是什么?

Revolt是并发PHP应用程序的坚如磐石的事件循环。通常的PHP应用程序将大部分时间花在等待I/O上。虽然PHP是单线程的,但可以使用协作多任务来允许并发性,方法是使用等待时间来做不同的事情。j1628资讯网——每日最新资讯28at.com

PHP的传统同步执行流程很容易理解。一次只做一件事。如果查询数据库,则发送查询并等待数据库服务器的响应。一旦你有了答案,你就可以开始做下一件事。j1628资讯网——每日最新资讯28at.com

ReactPHP和其他库已经在PHP中提供了很长一段时间的协作多任务。然而,它们的事件驱动特性与许多现有的接口不兼容,需要不同的思维模型。PHP 8.1内置了fibers,它提供了协作多线程。调用可以是异步的,没有promise或回调,同时仍然允许非阻塞I/O。j1628资讯网——每日最新资讯28at.com

每个使用协同多任务的应用程序都需要一个调度器(也称为事件循环),这个包提供了这个调度器。Revolt是结合了React和ReactPHP的事件循环实现的多年经验的结果。然而,它并不是一个用于编写并发PHP应用程序的成熟框架,而只是提供了必要的公共基础。不同的(强烈的)固执己见的库可以在它的基础上构建,React和ReactPHP将继续共存。j1628资讯网——每日最新资讯28at.com

Revolt 支持事件

  • Defer 回调在事件循环的下一次迭代中执行。如果有延迟调度,事件循环不会在迭代之间等待。
  • Delay 在指定的秒数后执行回调。秒的分数可以表示为浮点数。
  • Repeat 在指定的秒数后重复执行回调。秒的分数可以表示为浮点数。
  • Stream readable 当流上有数据要读取或连接关闭时,将执行回调。
  • Stream writable 当写缓冲区中有足够的空间来接受要写入的新数据时,就会执行回调。
  • Signal 当进程从操作系统接收到特定信号时执行回调。

安装

composer require revolt/event-loop

注意:此包可以作为Composer依赖项安装在PHP 8.1及更高版本上。j1628资讯网——每日最新资讯28at.com

示例

<?phprequire __DIR__ . '/vendor/autoload.php';use Revolt/EventLoop;$suspension = EventLoop::getSuspension();$repeatId = EventLoop::repeat(1, function (): void {    print '++ Executing callback created by EventLoop::repeat()' . PHP_EOL;});EventLoop::delay(5, function () use ($suspension, $repeatId): void {    print '++ Executing callback created by EventLoop::delay()' . PHP_EOL;    EventLoop::cancel($repeatId);    $suspension->resume(null);    print '++ Suspension::resume() is async!' . PHP_EOL;});print '++ Suspending to event loop...' . PHP_EOL;$suspension->suspend();print '++ Script end' . PHP_EOL;

在执行上面的例子时,你应该看到这样的输出:j1628资讯网——每日最新资讯28at.com

++ Suspending to event loop...++ Executing callback created by EventLoop::repeat()++ Executing callback created by EventLoop::repeat()++ Executing callback created by EventLoop::repeat()++ Executing callback created by EventLoop::repeat()++ Executing callback created by EventLoop::delay()++ Suspension::resume() is async!++ Script end

这个输出说明了事件循环内部发生的事情就像它自己独立的程序一样。您的脚本将不会继续通过 $suspension->suspend() 点,除非挂起点通过 $suspension->resume() 或 $suspension->throw() 恢复。j1628资讯网——每日最新资讯28at.com

虽然一个应用程序可以而且经常几乎完全在事件循环的范围内发生,但我们也可以使用事件循环来做一些事情,比如下面的例子,它为交互式控制台输入施加了一个短暂的超时:j1628资讯网——每日最新资讯28at.com

<?phprequire __DIR__ . '/vendor/autoload.php';use Revolt/EventLoop;if (/stream_set_blocking(STDIN, false) !== true) {    /fwrite(STDERR, "Unable to set STDIN to non-blocking" . PHP_EOL);    exit(1);}print "Write something and hit enter" . PHP_EOL;$suspension = EventLoop::getSuspension();$readableId = EventLoop::onReadable(STDIN, function ($id, $stream) use ($suspension): void {    EventLoop::cancel($id);    $chunk = /fread($stream, 8192);    print "Read " . /strlen($chunk) . " bytes" . PHP_EOL;    $suspension->resume(null);});$timeoutId = EventLoop::delay(5, function () use ($readableId, $suspension) {    EventLoop::cancel($readableId);        print "Timeout reached" . PHP_EOL;    $suspension->resume(null);});$suspension->suspend();EventLoop::cancel($readableId);EventLoop::cancel($timeoutId);

显然,我们可以在这个例子中简单地同步使用 fgets(STDIN) 。我们只是在演示可以根据需要进出事件循环,以混合同步任务和非阻塞任务。j1628资讯网——每日最新资讯28at.com

Timers 定时器

事件循环公开了几种调度计时器的方法。j1628资讯网——每日最新资讯28at.com

Deferred 回调j1628资讯网——每日最新资讯28at.com

  • defer() 调度回调在事件循环的下一次迭代中执行。
  • 此方法保证了一个干净的调用堆栈,以避免循环的当前迭代中其他事件的饥饿。defer()回调总是在事件循环的下一个tick中执行。
  • 在 defer()计时器执行之后,它会被事件循环自动垃圾收集,因此应用程序不需要手动取消关联的回调。
  • 像所有事件回调一样,defer() 计时器可以被禁用和重新启用。如果您在调度它和它实际运行之间禁用此回调,则事件循环将无法对其进行垃圾收集,直到它执行为止。因此,如果 defer() 回调从未真正执行以释放任何相关资源,则必须手动取消该回调。

案例j1628资讯网——每日最新资讯28at.com

<?php/** * @author Tinywan(ShaoBo Wan) * @email 756684177@qq.com * @date 2024/1/31 18:24 */require 'vendor/autoload.php';use Revolt/EventLoop;echo "line 1/n";EventLoop::defer(function (): void {    echo "line 3/n";});echo "line 2/n";EventLoop::run();

输出j1628资讯网——每日最新资讯28at.com

line 1line 2line 3

Delayed 回调j1628资讯网——每日最新资讯28at.com

  • delay() 计划在延迟 n 秒后执行回调
  • delay() 回调在执行后也会被事件循环自动垃圾回收,应用程序不应该手动取消它,除非他们希望在执行前完全放弃回调。
  • 被禁用的 delay() 回调会重置其延迟时间,以便重新启用后,原始延迟时间再次从零开始。
  • 与 defer() 回调一样,如果定时器在创建后被应用程序禁用而无法运行,则必须手动取消计划用于一次性执行的定时器以释放资源。

案例j1628资讯网——每日最新资讯28at.com

<?php/** * @author Tinywan(ShaoBo Wan) * @email 756684177@qq.com * @date 2024/1/31 18:24 */require 'vendor/autoload.php';use Revolt/EventLoop;EventLoop::delay(3, function (): void {    print '3 seconds passed';});EventLoop::run();

3秒后输出j1628资讯网——每日最新资讯28at.com

3 seconds passed

Periodic 定期回调j1628资讯网——每日最新资讯28at.com

  • repeat() 调度回调以每 n 秒重复执行一次。
  • 与所有其他事件回调一样, repeat() 定时器可以随时禁用/重新启用。
  • 与 defer() 和 delay() 回调不同, repeat() 回调必须显式取消以释放关联的资源。一旦 repeat() 回调的目的实现,如果不能通过 cancel() 释放它们,将导致应用程序中的内存泄漏。仅仅禁用 repeat() 回调是不够的,因为它们的数据只有在取消时才被释放。

案例j1628资讯网——每日最新资讯28at.com

<?php/** * @author Tinywan(ShaoBo Wan) * @email 756684177@qq.com * @date 2024/1/31 18:49 */require 'vendor/autoload.php';use Revolt/EventLoop;EventLoop::repeat(0.1, function ($callbackId): void {    static $i = 0;    if ($i++ < 3) {        echo "tick/n";    } else {        EventLoop::cancel($callbackId);    }});EventLoop::run();

输出j1628资讯网——每日最新资讯28at.com

tickticktick

定时器偏差j1628资讯网——每日最新资讯28at.com

重复计时器基本上是简单的延迟计时器,在触发适当的处理程序之前会自动重新调度。它们受定时器漂移的影响。多个计时器可能会堆叠在一起,以防它们作为协程执行。j1628资讯网——每日最新资讯28at.com

Fibers 纤程

Revolt被设计为可以很好地与纤维一起工作。所有事件回调都在单独的纤程中运行,并且可以随时挂起它。如果在事件回调中没有挂起,则纤程将被重用于将来的事件回调以保存资源。j1628资讯网——每日最新资讯28at.com

挂起允许通过挂起当前执行上下文来等待事件,直到所讨论的事件发生。它们将挂起当前纤程并返回到事件循环,或者如果从纤程外部(即从 {main} )调用,则开始运行事件循环。j1628资讯网——每日最新资讯28at.com

应使用 Revolt/EventLoop/Suspension API暂停和恢复光纤。Suspension 对象可以使用 Revolt/EventLoop::getSuspension() 创建。在获得 Suspension 对象之后,可以注册事件回调以调度当前纤程的恢复。$suspension->suspend() 将挂起当前的执行上下文,直到它通过 $suspension->resume() 或 $suspension->throw()恢复。j1628资讯网——每日最新资讯28at.com

案例:让我们暂停主执行上下文,直到有数据从 STDIN 读取或超时到期:j1628资讯网——每日最新资讯28at.com

<?phprequire __DIR__ . '/vendor/autoload.php';use Revolt/EventLoop;if (/stream_set_blocking(STDIN, false) !== true) {    /fwrite(STDERR, "Unable to set STDIN to non-blocking" . PHP_EOL);    exit(1);}print "Write something and hit enter" . PHP_EOL;$suspension = EventLoop::getSuspension();$readableId = EventLoop::onReadable(STDIN, function ($id, $stream) use ($suspension): void {    EventLoop::cancel($id);    $chunk = /fread($stream, 8192);    print "Read " . /strlen($chunk) . " bytes" . PHP_EOL;    $suspension->resume(null);});$timeoutId = EventLoop::delay(5, function () use ($readableId, $suspension) {    EventLoop::cancel($readableId);        print "Timeout reached" . PHP_EOL;    $suspension->resume(null);});$suspension->suspend();EventLoop::cancel($readableId);EventLoop::cancel($timeoutId);

自动超时输出j1628资讯网——每日最新资讯28at.com

Write something and hit enterTimeout reached

按Enter键盘输出j1628资讯网——每日最新资讯28at.com

Write something and hit enterRead 1 bytes

Signals 信号

信号是类Unix操作系统中的标准化消息。j1628资讯网——每日最新资讯28at.com

EventLoop::onSignal() 可用于对发送到进程的信号作出反应。j1628资讯网——每日最新资讯28at.com

<?phprequire __DIR__ . '/vendor/autoload.php';use Revolt/EventLoop;// Let's tick off output once per second, so we can see activity.EventLoop::repeat(1, function (): void {    echo "tick: ", date('c'), "/n";});// What to do when a SIGINT signal is receivedEventLoop::onSignal(SIGINT, function (): void {    echo "Caught SIGINT! exiting .../n";    exit;});EventLoop::run();

SIGINT 信号: 当用户按某些终端键时, 引发终端产生的信号. 如Ctrl+C键, 这将产生中断信号SIGINT. 它将停止一个已失去控制的程序。j1628资讯网——每日最新资讯28at.com

Ctrl+C 输出j1628资讯网——每日最新资讯28at.com

tick: 2024-01-31T11:54:03+00:00tick: 2024-01-31T11:54:04+00:00tick: 2024-01-31T11:54:05+00:00tick: 2024-01-31T11:54:06+00:00tick: 2024-01-31T11:54:07+00:00tick: 2024-01-31T11:54:08+00:00tick: 2024-01-31T11:54:09+00:00tick: 2024-01-31T11:54:10+00:00tick: 2024-01-31T11:54:11+00:00tick: 2024-01-31T11:54:12+00:00^CCaught SIGINT! exiting ...

从基本原理中可以清楚地看到,信号回调可以像任何其他事件回调一样被启用、禁用和取消。一般来说,如果所有回调都消失了,只有信号回调仍然存在,那么您希望退出事件循环,除非您没有主动等待该事件发生。j1628资讯网——每日最新资讯28at.com

信号号可用性

ext-uv 暴露 UV::SIG* 常量用于可观察信号。使用 EventDriver 的应用程序在注册信号回调或依赖 ext-pcntl 时需要手动指定适当的整数信号编号。j1628资讯网——每日最新资讯28at.com


j1628资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-70393-0.htmlPHP 高性能的事件循环库 Revolt

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 异步Rust:构建实时消息代理服务器

下一篇: 借助Nacos高效配置与实践Seata事务的TCC模式

标签:
  • 热门焦点
  • 对标苹果的灵动岛 华为带来实况窗功能

    继苹果的灵动岛之后,华为也在今天正式推出了“实况窗”功能。据今天鸿蒙OS 4.0的现场演示显示,华为的实况窗可以更高效的展现出实时通知,比如锁屏上就能看到外卖、打车、银行
  • 小米降噪蓝牙耳机Necklace分享:听一首歌 读懂一个故事

    在今天下午的小米Civi 2新品发布会上,小米还带来了一款新的降噪蓝牙耳机Necklace,我们也在发布结束的第一时间给大家带来这款耳机的简单分享。现在大家能见到最多的蓝牙耳机
  • 小米平板5 Pro 12.4简评:多专多能 兼顾影音娱乐的大屏利器

    疫情带来了网课,网课盘活了安卓平板,安卓平板市场虽然中途停滞了几年,但好的一点就是停滞的这几年行业又有了新的发展方向,例如超窄边框、高刷新率、多摄镜头组合等,这就让安卓
  • Raft算法:保障分布式系统共识的稳健之道

    1. 什么是Raft算法?Raft 是英文”Reliable、Replicated、Redundant、And Fault-Tolerant”(“可靠、可复制、可冗余、可容错”)的首字母缩写。Raft算法是一种用于在分布式系统
  • 微信语音大揭秘:为什么禁止转发?

    大家好,我是你们的小米。今天,我要和大家聊一个有趣的话题:为什么微信语音不可以转发?这是一个我们经常在日常使用中遇到的问题,也是一个让很多人好奇的问题。让我们一起来揭开这
  • 一文搞定Java NIO,以及各种奇葩流

    大家好,我是哪吒。很多朋友问我,如何才能学好IO流,对各种流的概念,云里雾里的,不求甚解。用到的时候,现百度,功能虽然实现了,但是为什么用这个?不知道。更别说效率问题了~下次再遇到,
  • 本地生活这块肥肉,拼多多也想吃一口

    出品/壹览商业 作者/李彦编辑/木鱼拼多多也看上本地生活这块蛋糕了。近期,拼多多在App首页&ldquo;充值中心&rdquo;入口上线了本机生活界面。壹览商业发现,该界面目前主要
  • 东方甄选单飞:有些鸟注定是关不住的

    作者:彭宽鸿来源:华尔街科技眼&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;&zwj;东方甄选创始人俞敏洪带队的&ldquo;7天甘肃行&rdquo;直播活动已在近日顺利收官。成立后一
  • Meta盲目扩张致超万人被裁,重金押注元宇宙而前景未明

    图片来源:图虫创意日前,Meta创始人兼CEO 马克&middot;扎克伯发布公开信,宣布Meta计划裁员超11000人,占其员工总数13%。他公开承认了自己的预判失误:&ldquo;不仅
Top