伦敦Perl和Raku研讨会于2024年10月26日举行。如果您的公司依赖Perl,请考虑赞助和/或参加.

名称

EV-perl与libev的接口,这是一个高性能的全功能事件循环

简介

使用电动汽车;#计时器my$w=EV::计时器2,0,sub{警告“2s后调用”;};my$w=EV::计时器2、2、sub{warn“大约每2秒调用一次(repeat=2)”;};undef$w;#未定义再次销毁事件监视程序my$w=EV::周期0,60,0,sub{警告“每分钟、每分钟、准确地调用”;};#IO(输入输出)my$w=EV::io*STDIN,EV::READ,sub{my($w,$revents)=@_;#所有回调都接收观察程序和事件掩码警告“stdin可读,您输入了:”,<stdin>;};#信号my$w=EV::信号“QUIT”,sub{警告“收到sigquit”;};#儿童/PID状态更改我的$w=EV::child 666,0,sub{my($w,$revents)=@_;我的$status=$w->rstatus;};#统计数据变化my$w=EV::stat“/etc/passwd”,10,sub{my($w,$revents)=@_;warn$w->path,“不知怎么改变了。\n”;};#主回路EV::运行;#循环,直到调用EV::break或所有观察者停止EV::运行EV::run_ONCE;#阻止,直到可以处理至少一个事件EV::运行EV::run_NOWAIT;#尝试处理相同的事件,但不要阻止

开始使用本模块之前

如果您只需要计时器、I/O、信号、子和空闲观察程序,而不需要此模块的高级功能,请考虑使用任何事件相反,特别是中描述的简化API不良事件.

当使用EV作为后端时不良事件API与本机一样快电动汽车API,但您的程序/模块仍将与许多其他事件循环一起运行。

描述

此模块为libev提供了一个接口(http://software.schmorp.de/pkg/libev.html)。虽然下面的文档很全面,但也可以参考libev本身的文档(http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.podperldoc EV::libev)有关watcher语义的更详细信息,或有关可用后端的一些讨论,或如何使用LIBEV_堵塞或者只是因为它有更详细的信息。

此模块非常快速且可扩展。它实际上非常快,您可以通过任何事件模块,保持对其他事件循环的可移植性(如果您不依赖任何通过它不可用的观察程序类型),并且仍然比Perl当前支持的任何其他事件循环更快。

EV 3.X至4.X的端口

EV版本4引入了此处总结的一些不兼容更改。根据libev使用的折旧策略,存在一个兼容层,因此程序应继续保持不变(XS接口缺少该层,因此使用该层的程序需要更新)。

此兼容层将在未来的某个版本中关闭。

与Perl相关的所有更改都是符号、函数和方法的重命名:

EV::回路=>EV::运行EV::LOOP_NONBLOCK=>EV::RUN_NOWAITEV::LOOP_ONESHOT=>EV::RUN_ONCEEV::卸载=>EV::中断EV::UNLOOP_CANCEL=>EV::中断_取消EV::UNLOOP_ONE=>EV::BREAK_ONEEV::unlop_ALL=>EV::BREAK_ALLEV::超时=>EV::计时器EV::loop_count=>EV::iterationEV::loop_depth=>EV::depthEV::loop_verify=>EV::verify

与上述函数对应的循环对象方法也进行了类似的重命名。

模块出口

此模块不导出任何符号。

事件循环

EV支持多个事件循环:有一个“默认事件循环”可以处理所有事情,包括信号和子观察程序,还有任意数量的“动态事件循环”,可以使用不同的后端(具有各种限制),但没有子观察程序和信号观察程序。

您无需执行任何操作即可创建默认事件循环:当加载模块时,在选择工作后端的前提下选择合适的后端(例如,这将排除大多数BSD上的kqueue)。除非模块有“特殊需要”,否则应该始终使用默认循环,因为这是最快的(perl-wise),最好由其他模块(例如AnyEvent或Coro)和最可移植的事件循环支持。

对于特定程序,可以动态创建其他事件循环。

如果您想利用kqueue(通常只适用于套接字),即使默认循环没有启用它,您也可以嵌入将kqueue循环转换为默认循环:运行默认循环也会在一定程度上为kqueue环路提供服务。有关如何实现这一点的示例,请参阅关于嵌入观察者的部分中的示例。

$loop=新EV::loop[$flags]

根据指定的标志创建一个新的事件循环。请参阅ev_loop_new()libev文档中的函数描述(http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#GLOBAL_FUNCTIONS,或本地安装为企业价值::libevmanpage)了解更多信息。

当任何观察者不再引用循环并且循环对象超出范围时,循环将自动被销毁。

如果不嵌入循环,则使用EV::FLAG_FORKCHECK(警告检查)建议使用,因为此模块仅保护默认事件循环。如果你将此循环嵌入默认循环中,这是不必要的,因为EV::嵌入自动在fork上执行正确的操作。

$loop->loop_fork

在进入或继续事件循环之前,必须在子级中的fork之后调用。另一种方法是使用EV::FLAG_FORKCHECK(警告检查)它会自动调用此函数,但性能会有所损失(请参阅libev文档)。

$loop->验证

电话ev_verify(验证)进行内部一致性检查(用于调试libev),并在发现任何数据结构损坏时中止程序。

$loop=EV::default_loop[$flags]

返回默认循环(这是一个单一对象)。由于此模块已经使用默认标志创建了默认循环,因此在此处指定标志将不会产生任何效果,除非您首先销毁默认循环,这是不受支持的。所以简而言之:不要这样做,如果你打破了它,你就可以保留碎片。

基本接口

$EV::死亡

必须包含对回调抛出异常时调用的函数的引用($@包含错误)。默认情况下打印信息消息并继续。

如果此回调抛出异常,它将被自动忽略。

$flags=EV::supported_backends
$flags=EV::recommended_backends
$flags=EV::embeddable_backends

返回集合(请参见EV::后端_*标志)、该平台的一组推荐后端(应该是好的)和一组可嵌入后端(参见嵌入式手表)。

EV::休眠$秒

在给定的秒数(小数)内阻止进程。

$时间=EV::时间

返回自epoch以来的当前时间(小数)秒。

$time=EV::现在
$time=$loop->现在

返回上次事件循环迭代开始的时间。这是(相对)计时器所基于的时间,引用它通常比调用EV::time更快。

EV::now_update(当前更新)
$loop->now_update

通过查询内核来建立当前时间,更新返回的时间EV::现在正在进行中。这是一项成本高昂的操作,通常在EV::运行.

这个函数很少有用,但当某些事件回调运行很长时间而没有进入事件循环时,更新libev对当前时间的想法是一个好主意。

EV::暂停
$loop->挂起
EV::恢复
$loop->恢复

这两个函数暂停并恢复一个循环,以便在一段时间内不使用循环且不应处理超时时使用。

典型的用例是交互式程序,如游戏:当用户按下^Z要暂停游戏并在一个小时后恢复,最好将超时处理为程序暂停时没有实际时间。这可以通过调用暂停在您的SIGTSTP公司处理程序,向自己发送SIGSTOP公司和呼叫简历然后直接恢复计时器处理。

有效地,所有计时器观察者将被两次之间的时间延迟暂停简历,以及所有周期性的观察者将被重新安排(也就是说,他们将丢失暂停时发生的任何事件)。

打电话后暂停不能呼叫任何给定循环上的函数,而不是简历,还有你不能呼叫简历之前没有呼叫暂停.

打电话暂停/简历具有更新事件循环时间的副作用(请参见现在更新(_U)).

$backend=EV::backend
$backend=$loop->后端

返回描述libev使用的后端的整数(EV::backend_SELECT或EV::backend_EPOLL)。

$active=EV::运行[$flags]
$active=$loop->运行([$flags])

开始检查事件并调用回调。当回调调用EV::break或标志为非零时(在这种情况下,返回值为true),或者当没有引用循环的活动观察程序时(keepalive为true时),返回值将为false。返回值通常可以解释为“如果为true,则还有更多工作要做”。

$flags参数可以是以下之一:

0同上EV::RUN_ONCE块最多一次(等待,但不要循环)EV::RUN_NOWAIT根本不阻塞(获取/处理事件,但不等待)
EV::中断[$how]
$loop->break([$how])

如果调用时没有参数或参数为EV::BREAK_ONE,则对EV::run return进行最内层的调用。

当使用EV::BREAK_ALL参数调用时,所有对EV::run的调用都将尽快返回。

当使用EV::BREAK_CANCEL参数调用时,任何挂起的中断都将被取消。

$count=EV::迭代
$count=$loop->迭代

返回事件循环轮询新事件的次数。有时用作生成计数器。

EV::一次$fh_or_undef,$events,$timeout,$cb->($revents)
$loop->一次($fh_or_undef、$events、$timeout、$cb->($revents))

此函数将单个单发事件的I/O和计时器观察程序滚动在一起,而无需管理观察程序对象。

如果$fh或_undef是文件句柄或文件描述符,则$个事件必须是包含以下内容之一的位集EV::读取,EV::写入EV::读| EV::写,指示要等待的I/O事件类型。如果不想等待某些I/O事件,请指定未定义对于$fh或_undef0对于$个事件).

如果超时为未定义或者为负数,则没有超时。否则EV::计时器将使用此值启动。

当发生错误或触发超时或I/O观察程序时,将使用接收到的事件集调用回调(通常您可以期望它是以下内容的组合EV::错误,EV::读取,EV::写入EV::计时器).

EV::once不返回任何内容:观察程序保持活动状态,直到其中任何一个触发,然后将停止并释放它们,并调用回调。

EV::feed_fd_event$fd,$revents
$loop->feed_event($fd,$revents)

将文件描述符上的事件馈送到EV。EV将对此调用作出响应,如同$复仇(以下各项的组合EV::读取EV::写入)发生在文件描述符上美元fd.

EV::feed_signal_event$信号

将信号事件馈送到默认循环中。EV将对此呼叫作出响应,如同$信号发生了。

EV::feed_signal$信号

将信号事件输入电动汽车-不同于电动车辆::feed_signal_event,无论哪个循环注册了信号,这都是有效的,并且主要用于自定义信号实现。

EV::set_io_collect_interval$time
$loop->set_io_collect_interval($time)
EV::set_timeout_collect_interval$时间
$loop->set_timeout_collect_interval($time)

这些高级函数设置轮询I/O事件时的最小块间隔和计时器事件的最小等待间隔。请参阅libev文档,网址为http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#FUNCTIONS_CONTROLLING_THE_EVENT_LOOP(本地安装为企业价值::libev)以进行更详细的讨论。

$count=EV::pending_count
$count=$loop->pending_count

返回当前挂起的观察程序数。

EV::调用挂起
$loop->调用挂起

调用所有当前挂起的观察程序。

观察者对象

观察者是一个创建用于记录您对某些事件的兴趣的对象。例如,如果您希望等待STDIN变为可读,您可以创建一个EV::io观察程序:

my$watcher=EV::io*STDIN,EV::READ,sub{my($watcher,$revents)=@_;警告“是的,STDIN现在应该是可读的,没有阻塞!\n”};

所有观察者都可以处于活动状态(等待事件)或非活动状态(暂停)。只有活动的观察者才会调用其回调。所有回调都将使用至少两个参数进行调用:观察程序和接收事件的位掩码。

每种观察程序类型都在revents中有其关联的位,因此您可以对多个观察程序使用相同的回调。事件掩码以类型命名,即EV::child set EV::child,EV::prepare set EV::prepare,EV::periodic set EV:∶periodic等,但i/O事件除外(它可以设置EV::READ和EV::WRITE位)。

在极少数情况下,如果希望创建观察程序但不同时启动它,则每个构造函数都有一个带有尾随的变量_纳秒在其名称中,例如EV::io有一个非启动变量EV::io_ns等。

请注意,当观察程序对象被销毁时,观察程序将自动停止,因此您需要保存构造函数返回的观察程序对象。

此外,如果观察程序处于活动状态,所有更改观察程序某些方面的方法(->设置、->优先级、->fh等)都会自动停止并再次启动它,这意味着挂起的事件会丢失。

常见的监视方法

本节列出了所有观察者通用的方法。

$w->开始

如果观察程序尚未处于活动状态,则启动该观察程序。对已激活的观察程序不执行任何操作。默认情况下,所有观察程序都以活动状态启动(请参阅_纳秒变量(如果需要停止观察程序)。

$w->停止

如果监视程序处于活动状态,请将其停止。同时清除所有挂起的事件(已收到但尚未导致回调调用的事件),无论观察程序是否处于活动状态。

$bool=$w->处于活动状态

如果观察程序处于活动状态,则返回true,否则返回false。

$current_data=$w->数据
$old_data=$w->数据($new_data)

查询观察程序上可自由使用的数据标量,并可选择更改它。这是将自定义数据与观察程序关联的一种方法:

my$w=EV::计时器60,0,sub{警告$_[0]->数据;};$w->数据(“打印我!”);
$current_cb=$w->cb
$old_cb=$w->cb($new_cb)

查询观察程序上的回调并有选择地更改它。您可以随时执行此操作,而无需重新启动观察程序。

$current_priority=$w->优先级
$old_priority=$w->优先级($new_prioriity)

查询观察程序的优先级并有选择地更改它。优先级较高的挂起观察程序将首先被调用。优先级的有效范围介于EV::MAXPRI(默认值2)和EV::MINPRI(默认值-2)之间。如果优先级在该范围之外,它将自动标准化为最接近的有效优先级。

任何新创建的观察程序的默认优先级为0。

请注意,优先级语义还没有得到充实,并且可能会发生几乎确定的更改。

$w->调用($revents)

使用给定的事件掩码立即调用回调。

$w->feed_event($revents)

将此观察者的一些事件输入EV。EV将对此调用作出反应,就像观察者收到给定的$复仇面具。

$revents=$w->清除挂起

如果观察程序处于挂起状态,此函数将清除其挂起状态并返回其$复仇位集(就像调用了它的回调一样)。如果观察程序没有挂起,它什么也不做并返回0.

$previous_state=$w->keepalive($bool)

通常情况下,EV::运行将在没有活动观察程序时返回(这是一个“死锁”,因为无法再取得任何进展)。这很方便,因为它可以让你启动你的观察者(和你的工作),打电话EV::运行当它返回时,您知道您的所有作业都已完成(或者他们忘记为任务注册一些观察者:)。

然而,有时这会妨碍您,例如当调用EV::运行(通常是主程序)与长寿观察程序不是同一个模块(例如,甚至是其他人编写的DNS客户端模块)。然后,您可能希望处理任何未完成的请求,但不希望保留EV::运行因为您碰巧有这个长时间运行的UDP端口观察程序,所以不会返回。

在这种情况下,您可以清除keepalive状态,这意味着即使您的观察程序处于活动状态,它也不会保持EV::运行从返回。

keepalive的初始值为true(enabled),您可以随时更改它。

示例:为某些UDP套接字注册I/O观察程序,但不要仅仅因为该观察程序而阻止事件循环运行。

my$udp_socket=。。。my$udp_watcher=EV::io$udp_socket,EV::READ,sub{…};$udp_watcher->keepalive(0);
$loop=$w->循环

返回此观察程序附加到的循环。

守望者类型

以下各小节描述了单个观察者类型。

I/O WATCHERS-这个文件描述符可读写吗?

$w=EV::io$fileno_or_fh,$eventmask,$callback
$w=EV::io_ns$fileno_or_fh,$eventmask,$callback
$w=$loop->io($fileno_or_fh,$eventmask,$callback)
$w=$loop->io_ns($fileno_or_fh、$eventmask、$callback)

只要返回的观察程序对象是活动的,就调用$回调当中指定了至少一个事件时$事件掩码发生。

$eventmask可以是这些常量中的一个或多个,或将其组合在一起:

EV::READ等待READ()不再阻塞EV::WRITE等待WRITE()不再阻塞

这个io(_N)variant不会启动(激活)新创建的观察程序。

$w->集合($fileno_or_fh,$eventmask)

重新配置观察程序,有关详细信息,请参阅上面的构造函数。可以随时拨打。

$current_fh=$w->fh
$old_fh=$w->fh($new_fh)

返回以前设置的文件句柄,并可以选择设置一个新的文件句柄。

$current_eventmask=$w->事件
$old_eventmask=$w->事件($new_eventmak)

返回以前设置的事件掩码,并可以选择设置新的事件掩码。

计时器计时器-相对和可选重复超时

$w=EV::计时器$after、$repeat、$callback
$w=EV::timer_ns$之后,$repeat,$callback
$w=$loop->计时器($after、$repeat、$callback)
$w=$loop->timer_ns($after、$repeat、$callback)

在之后调用回调之后$秒(可以是分数或负数)。如果$重复非零,则在回调返回后,计时器将重新启动($repeat值为$after)。

这意味着回调将在之后$秒,然后每隔$重复秒。计时器尽其所能不漂移,但它调用计时器的频率不会高于每次事件循环迭代一次,在其他情况下可能会漂移。如果这是不可接受的,那么看看EV::periodical,它可以提供长期稳定的定时器。

计时器基于一个单调的时钟,也就是说,如果有人在计时器运行时坐在机器前面并更改系统时钟,那么计时器将(大致)以相同的时间运行。

这个计时器_nsvariant不会启动(激活)新创建的观察程序。

$w->集合($after,$repeat=0)

重新配置观察程序,有关详细信息,请参阅上面的构造函数。可以随时拨打。

$w->再次
$w->再次($repeat)

类似于开始方法,但具有重复计时器的特殊语义:

如果计时器处于活动状态且不重复,它将被停止。

如果计时器处于活动状态并重复,则将超时重置为发生$重复几秒钟后。

如果计时器处于非活动状态并重复,请使用重复值启动它。

否则什么也不做。

当某些IO操作超时时,此行为很有用。为创建一个具有相同值的计时器对象之后$$重复,然后在读/写观察程序中运行再一次方法。

如果调用时使用$重复参数,然后它使用这个计时器重复值。

$after=$w->剩余

计算并返回计时器启动前的剩余时间。

$repeat=$w->重复
$old_repeat=$w->重复($new_repeate)

返回repeat属性的当前值,并可以选择设置一个新值。设置新的值不会重新启动观察程序-如果观察程序处于活动状态,则每当下次过期时都会使用新的重复值。

周期性监视程序-到cron还是不到cron?

$w=EV::周期性$at,$interval,$rescheme_cb,$callback
$w=EV::periodic_ns$at,$interval,$reschedule_cb,$callback
$w=$loop->periodic($at,$interval,$reschedule_cb,$callback)
$w=$loop->periodic_ns($at,$interval,$reschedule_cb,$callback)

与EV::计时器类似,但不是基于相对超时,而是基于绝对时间。除了创建“在”指定时间触发的“简单”计时器外,它还可以用于非漂移绝对计时器和不受时间跳跃不利影响的更复杂、类似cron的设置(即,当系统时钟被显式日期s或其他方式(如ntpd)更改时)。它也是电动汽车中最复杂的观察者类型。

它有三种不同的“模式”:

  • 绝对计时器($interval=$rescheme_cb=0)

    这次只需在挂钟时间点火美元于而且不会重复。当发生时间跳跃时,它不会进行调整,也就是说,如果它将在2011年1月1日运行,那么它将在系统时间达到或超过此时间时运行。

  • 重复间隔计时器($interval>0,$reschedule_cb=0)

    在这种模式下,观察者总是被安排在下一次超时$at+N*$间隔时间(对于最小的整数N),然后重复,而不考虑任何时间跳跃。注意,由于N个可以是负数,第一次触发可能发生在美元于.

    这可用于创建不随系统时间漂移的计时器:

    my$hourly=EV::周期性0,3600,0,sub{打印“一次/小时\n”};

    这并不意味着触发器之间总是有3600秒的间隔,但只有当系统时间显示完整小时(UTC)时才会调用回调。

    另一种思考方式(对于数学倾向的人来说)是,EV::periodical将尝试在下一个可能的时间以这种模式运行回调$time=$at(mod$interval),不考虑任何时间跳跃。

  • 手动重新调度模式($reschedule_cb=coderef)

    在此模式下,$interval和$at都将被忽略。相反,每次周期性观察程序被调度时,都会以观察程序作为第一个参数,以当前时间作为第二个参数调用重新调度回调($reschedule_cb)。

    此回调永远不能停止或破坏此或任何其他定期观察程序,也不能调用任何事件循环函数或方法。如果需要停止,请返回1e30,然后停止。您可以创建并启动EV::准备此任务的观察者。

    它必须根据传递的时间值(即大于或等于第二个参数的最小时间值)返回下一次触发的时间。它通常会在触发回调之前调用,但也可能在其他时间调用。

    这可以用于创建非常复杂的计时器,例如在每个午夜、本地时间(实际上是最后一个午夜之后的一天,以保持示例简单)触发的计时器:

    my$daily=EV::周期0,0,sub{my($w,$现在)=@_;使用时间::本地();my(undef、undef和undef,$d、$m和$y)=本地时间$现在;时间::本地::timelocal_nocheck 0、0、0,$d+1、$m、$y},子{打印“现在是午夜或可能很快之后”;};

这个周期_nsvariant不会启动(激活)新创建的观察程序。

$w->集合($at、$interval、$reschedule_cb)

重新配置观察程序,有关详细信息,请参阅上面的构造函数。可以随时拨打。

$w->再次

只需再次停止并启动观察程序。

$time=$w->时间

返回预期观察程序下次触发的时间。

$offset=$w->偏移
$old_offset=$w->偏移量($new_offset)

返回偏移量属性的当前值,并可以选择设置新值。设置新值不会重新启动观测器-如果观测器处于活动状态,则在下次过期时使用新的偏移值。

$interval=$w->interval
$old_interval=$w->间隔($new_interval)

有关间隔属性,请参见上文。

$rescheme_cb=$w->rescheme_cb
$old_reschedule_cb=$w->重新调度_cb($new_reschedule_cb)

有关重新安排回调,请参见上文。

信号观测器-当信号发出时,给我发信号!

$w=EV::信号$signal,$callback
$w=EV::signal_ns$signal,$callback
$w=$loop->信号($signal,$callback)
$w=$loop->signal_ns($signal,$callback)

当接收到$信号时调用回调(信号可以通过数字或名称指定,就像杀死%SIG公司).

只有一个事件循环可以捕获给定的信号-试图从两个EV循环捕获相同的信号将立即导致程序崩溃或导致数据损坏。

当您启动信号观测器时,EV将获取进程的信号(内核一次只允许一个组件接收信号),并在您停止它时再次将其删除。当您向%SIG公司,所以小心。

每个信号可以有任意多个信号观测器。

这个信号_nsvariant不会启动(激活)新创建的观察程序。

$w->设置($signal)

重新配置观察程序,有关详细信息,请参阅上面的构造函数。可以随时拨打。

$current_signum=$w->信号
$old_signum=$w->信号($new_signal)

返回先前设置的信号(始终作为数字而非名称),并可选择设置一个新信号。

儿童看护员-注意过程状态的变化

$w=EV::child$pid、$trace、$callback
$w=EV::child_ns$pid、$trace、$callback
$w=$loop->child($pid、$trace、$callback)
$w=$loop->child_ns($pid、$trace、$callback)

当pid的状态更改时调用回调$pid(或任何pid,如果$pid为0)(当进程终止或终止时,或者当跟踪为真时,当它停止或继续时,会发生状态更改)。更准确地说:当进程收到SIGCHLD公司,EV将获取所有已更改/僵尸子级的未完成退出/等待状态,并调用回调。

在子级退出后但在事件循环开始其下一次迭代之前(例如,首先您,则新的子进程可能会退出,只有这样,您才能在新pid的父进程中安装一个子观察程序)。

您可以使用rstatus公司rpid公司watcher对象上的方法。

每个pid可以有任意多个pid观察程序,它们都会被调用。

这个子项(_N)variant不会启动(激活)新创建的观察程序。

$w->设置($pid,$trace)

重新配置观察程序,有关详细信息,请参阅上面的构造函数。可以随时拨打。

$current_pid=$w->pid

返回先前设置的进程id,并可以选择设置一个新的进程id。

$exit_status=$w->rstatus

返回exit/wait状态(如waitpid所返回的,请参阅perlfunc中的waitpid条目)。

$pid=$w->rpid

返回等待的子进程的pid(当您为所有pid安装了观察程序时很有用)。

EV::Child::reinit[实验]

在内部,libev为SIGCHLD公司不幸的是,很多Perl代码都像本地$SIG{CHLD},不幸的是,它已损坏,无法恢复信号处理程序。

如果发生这种情况,可以调用此函数来停止/重新启动内部libev观察器,这将重置信号处理程序。

请注意,这是一个实验函数,其接口可能会更改。

STAT WATCHERS-文件属性刚刚改变了吗?

$w=EV::stat$path,$interval,$callback
$w=EV::stat_ns$path,$interval,$callback
$w=$loop->stat($path、$interval、$callback)
$w=$loop->stat_ns($path、$interval、$callback)

在上检测到文件状态更改时调用回调$路径. The$路径不需要存在,从“path exists”更改为“path does not exist”与其他任何更改一样都是一种状态更改。

这个$间隔对于不存在或不支持OS支持的更改通知的系统,建议使用轮询间隔。如果您使用0然后使用未指定的默认值(强烈建议使用!),预计通常为5秒左右。

这种观察者类型并不适合大量的统计观察者,因为即使有支持操作系统的更改通知,这也可能是资源密集型的。

这个状态_nsvariant不会启动(激活)新创建的观察程序。

…=$w->统计

这个调用与perl非常相似统计内置:It统计(使用lstat卫星)watcher中指定的路径,并将perls stat缓存(以及EV对当前stat值的想法)设置为找到的值。

在标量上下文中,返回一个布尔值表示stat的成功或失败。在列表上下文中,与stat返回相同的13值列表(除了blksize和blocks字段不可靠之外)。

如果出现错误,errno设置为ENOENT公司(无论实际误差值如何)和nlink链接值被强制为零(如果stat成功,则nlink保证为非零)。

有关更多信息,请参阅下面的两个条目。

…=$w->属性

就像这样$w->状态,但没有初始状态:这将返回EV最近检测到的值。有关更多信息,请参阅下一项。

…=$w->上一个

就像这样$w->状态,但没有初始stat'ing:这将返回更改之前的一组值。

也就是说,当调用观察程序回调时,$w->以前将设置为找到的值之前检测到更改,而$w->属性返回发现的导致更改检测的值。两者之间的差异(如果有)上一个属性是什么触发了回调。

如果您对文件系统对象做了一些操作,并且不想触发另一个更改,可以调用统计更新EV对当前属性的想法。

$w->集合($path,$interval)

重新配置观察程序,有关详细信息,请参阅上面的构造函数。可以随时拨打。

$current_path=$w->路径
$old_path=$w->路径($new_path)

返回以前设置的路径,并可以选择设置一个新路径。

$current_interval=$w->间隔
$old_interval=$w->间隔($new_interval)

返回以前设置的间隔,并可以选择设置新的间隔。可用于查询实际使用的间隔。

空闲观察者-当你没有更好的事情要做时。。。

$w=EV::空闲$回调
$w=EV::idle_ns$回调
$w=$loop->空闲($callback)
$w=$loop->idle_ns($callback)

当没有其他具有相同或更高优先级的挂起观察程序时,调用回调(当然,不包括检查、准备和其他优先级相同或更低的空闲观察程序)。它们被称为空闲观察程序,因为当观察程序是流程中优先级最高的挂起事件时,流程将被视为处于该优先级的空闲状态。

如果你想要一个只有在其他活动尚未完成,您必须设置优先级EV::明尼苏达州.

只要有空闲观察程序处于活动状态,进程就不会阻塞,并且会反复调用它们,直到停止为止。

例如,如果您的优先级为空闲观察程序01,并优先使用I/O观察程序0,然后优先使用空闲观察程序1I/O观察程序将始终在准备就绪时运行。仅当空闲观察程序处于优先级时1已停止,I/O观察程序处于优先级0未与挂起0-调用优先级空闲观察程序。

这个空闲_nsvariant不会启动(激活)新创建的观察程序。

准备观察家-定制您的活动循环!

$w=EV::准备$回调
$w=EV::prepare_ns$回调
$w=$loop->准备($callback)
$w=$loop->prepare_ns($callback)

在进程阻塞之前调用回调。此时您仍然可以创建/修改任何观察程序。

有关解释和示例,请参阅下面的EV::check watcher。

这个prepare_ns(准备_秒)variant不会启动(激活)新创建的观察程序。

CHECK WATCHERS-定制更多事件循环!

$w=EV::检查$callback
$w=EV::check_ns$回调
$w=$loop->检查($callback)
$w=$loop->check_ns($callback)

在进程再次唤醒后(在收集事件后)调用回调,但在调用任何其他回调之前。

这可以用于将其他基于事件的软件集成到EV主循环中:您注册一个准备回调,然后在其中创建其他软件所需的io和计时器观测器。下面是集成Net::SNMP的真实示例(省略了一些详细信息):

我们的@snmp_watcher;我们的$snmp_prepare=EV::prepare sub{#除非处于活动状态,否则不执行任何操作$dispatcher->{_event_queue_h}或返回;#让调度员处理任何未完成的工作…未显示#为每个套接字创建I/O观察程序@snmp_watcher=((映射{EV::io$_,EV::READ,子{}}键%{$dispatcher->{_descriptors}}),EV::计时器+($event->[Net::SNMP::Dispatcher::_ACTIVE]? $事件->[Net::SNMP::Dispatcher::_TIME]-EV::now:0),0,子{},);};

回调是不相关的(甚至没有被调用),这些观察程序的唯一目的是在其中一个事件发生(套接字可读或计时器超时)时立即唤醒进程。相应的EV::check watcher随后将清理:

我们的$snmp_check=EV::check子{#摧毁所有观察者@snmp_watcher=();#让调度员处理任何新事物…未显示};

创建的观察程序的回调不会被调用,因为观察程序在这之前就被销毁了(记住EV::check首先被调用)。

这个选中(_N)variant不会启动(激活)新创建的观察程序。

EV::检查持续问题

与所有其他观察程序类型一样,有一个位掩码常量用于$复仇和其他地方。这个EV::检查是特殊的,因为它与检查Perl调用了sub。这不会对较新的perl(从5.8.9开始)造成大问题,但这意味着常数必须是内联,即运行时调用将不起作用。这意味着只要您始终使用EV然后EV::检查你是安全的。

FORK WATCHERS-在FORK之后恢复事件循环的大胆行为

叉()检测到。调用在事件循环接下来和之前阻塞之前完成检查守望者被叫来了,而且只有在叉子后面的孩子。

$w=EV::fork$回调
$w=EV::fork_ns$回调
$w=$loop->fork($callback)
$w=$loop->fork_ns($callback)

在fork之后的子进程中恢复事件循环之前调用回调。

这个分叉(_N)variant不会启动(激活)新创建的观察程序。

嵌入式监视程序-当一个后端不够时。。。

这是一种相当高级的观察程序类型,允许您将一个事件循环嵌入到另一个事件环中(嵌入式循环中当前仅支持IO事件,其他类型的观察程序可能会以延迟或不正确的方式处理,因此不能使用)。

请参阅libev文档,网址为http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#code_ev_embed_code_when_one_backend_(本地安装为电动汽车::libev)了解更多详细信息。

简而言之,此观察器在BSD系统上最有用,因为它不工作kqueue,所以仍然能够处理大量套接字:

我的$socket_loop;#检查是否支持使用SELECT或POLL _and_ KQUEUE如果((EV::backend&(EV::backend_POLL | EV::backend_SELECT))&&(EV::supported_backends&EV::embeddable_backenders&EV::BACKEND_KQUEUE)) {#对套接字使用kqueue$socket_loop=新EV::环路EV::BACKEND_KQUEUE | EV::FLAG_NOENV;}#否则使用默认循环$socket_loop | |=EV::default_loop;
$w=EV::嵌入$otherloop[,$callback]
$w=EV::embed_ns$otherloop[,$callback]
$w=$loop->嵌入($otherloop[,$callback])
$w=$loop->embed_ns($otherloop[,$callback])

嵌入式事件循环时调用回调($其他回路)具有任何I/O活动。这个$回调是可选的:如果它丢失了,那么嵌入式事件循环将被自动管理(建议这样做),否则您必须调用打扫你自己。

这个嵌入_个variant不会启动(激活)新创建的观察程序。

ASYNC WATCHERS-如何唤醒另一个事件循环

异步观察程序由EV提供,但在perl中几乎没有直接使用,因为perl既不支持并行运行的线程,也不支持直接访问信号处理程序或其他可能有价值的上下文。

然而,可以从XS级别使用它们。

有关详细信息,请参阅libev文档。

$w=EV::async$回调
$w=EV::async_ns$回调
$w=$loop->async($callback)
$w=$loop->async_ns($callback)
$w->发送
$bool=$w->async_pending

CLEANUP WATCHERS-如何在事件循环结束时进行清理

Perl级别不支持清理观察程序,目前只能通过XS使用。

PERL信号

Perl信号处理时(%SIG公司)不受EV的影响,EV的行为与任何其他C库相同:只有在Perl运行时才会处理Perl信号,这意味着只有在下次调用事件回调时才会调用信号处理程序。

解决方案是使用电动汽车信号观测器(参见EV::信号),这将确保对其他事件观察者进行适当操作。

如果由于任何原因无法执行此操作,还可以通过安装EV::检查观察者:

my$async_check=EV::check-sub{};

这可以确保perl在短时间内得到控制,以处理任何挂起的信号,还可以确保(稍微)降低总体操作速度。

ITHREADS公司

此模块无论如何都不支持Ithreads。Perl伪线程是邪恶的东西,必须消亡。完全支持Coro提供的真实线程(并且可以通过以下方式获得增强支持Coro::EV).

叉子

现代操作系统的大多数“改进”的事件传递机制在fork(2)方面都有不少问题(坦率地说:它不受支持,通常具有破坏性)。Libev提供了一个函数,该函数在子级中分叉后重新创建内核状态,从而可以解决这个问题。

在非win32平台上,此模块需要pthread_atfork功能来自动为您执行此操作。不过,这个函数在大多数BSD上都有很大的缺陷,所以YMMV也是如此。这样做的开销可以忽略不计,因为函数当前所做的一切都是设置一个标记,只有在下次使用事件循环时才会检查该标记,所以当您使用fork但不使用EV时,开销是最小的。

在win32上,没有fork的概念,所以这一切当然都不适用。

另请参阅

EV::MakeMaker-XS API的MakeMaker接口,EV::ADNS(异步DNS),闪光::EV(使Glib/Gtk2使用EV作为事件循环),企业价值::Glib(将Glib嵌入EV),Coro::EV(高效线程集成),网络::SNMP::EV(异步SNMP),任何事件用于事件无关和可移植的事件驱动编程。

作者

马克·莱曼<schmorp@schmorp.de>http://home.schmorp.de/