侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

perl AnyEvent简单介绍和入门知识

技术  /  管理员 发布于 6年前   581

什么是面向事件的编程(事件驱动的编程):

编程中所有的程序是由事件决定 C 可以是由用户操作(键盘,鼠标),也可以是由其他程序和流的到达或者操作系统事件(如网络数据包到达)来触发执行.

面向事件编程可以也被定义为,写一个计算机程序,在其中的代码(通常程序的功能的头部)被明确分配应用程序的主回路,其代码本身由两部分组成方法:事件和事件处理的代码。

面向事件的编程通常被应用在三种情况下:

1.创建用户界面的控制(包括图形)
2.创建一个基于服务器的应用程序
3.游戏编程时多个对象的管理

我们系统管理时,这种应用在服务器的应用程序中使用面向事件的编程很多,比如用于服务器应用解决10,000个并发连接(所谓 C10k 问题)

AnyEvent 是一个性能非常好的基于事件驱动的程序,有人使用它来解决 C10k 的问题,象平时我们写的程序,都是基于过程.我们都是先做完事件1-> 然后做事件2->然后做事件3 .这种方式.

但基于事件就完全不一样了,在主流程中你基本只有一个主体框架,程序的动作触发都是由事件来驱动.比如我们使用的窗口程序.点最大化最小化,都是基于事件,当接收到了最大化的事件做最大化事件那部分的程序开始运行.不在从头到尾部来执行.所以我们读基于事件的程序,最好是画成思维导图来帮助我们理解.

基于事件的程序常用到的最大好处是用来做异步,例如,我们要下载 100 个文件,下载完后对这些文件进行处理.可能给每个下载和处理的过程写成事件,这些事件可以同步运行(关键在于网络连接和进行文件的读写 IO 时要等待,事件是给这些等待复用起来).
不知大家了解 Perl 中的 select 这个功能不,就是等到句柄可以读或者写的时候,做不同的读或者写的操作.事件循环也是一样.

在整个 AnyEvent 入门中,我们只要关注二个点就行, WATCHERS(监控者) 和 条件变量.

WATCHERS(监控者)

在 select 中,有个角色叫"监控者",就是 select 函数本身.
在 AnyEvent 中不但可以监控 IO 还可以监控别的一些事件.来做不同的处理.我们可以看成这是不断的盯着某件事情的人
有如下几个基本的内置的可以用来盯着的事情("监控者").
TIMER : 监控时间,到了一定的条件,然后对不同的时间做不同的事件
I/O: 这个是监控到 IO 是否可以读写,然后做相应的事件
IDLE: 空闲时做什么事件
SIGNAL : 监控观查到不同的信息,调用相应的事件
CHILD PROCESS: 对子程序的状态来调用相应的处理事件

TIMER WATCHERS

基本语法

复制代码 代码如下:
AnyEvent->timer(
after => $seconds, # 多久之后做相应的操作.
interval => $seconds, # 在上面条件生效后,每格多久进行一次 callback.
cb => $cb, # cb 是 callback 的简写,所以知道了吧,只要到了前面的条件,就会运行 cb => 指向的函数.
);

使用实例:

下面的例子是,5 秒后,每 2 秒进行一次 callback 中的事件,直到 $w 这个注册的事件被 undef 为止(也就是 $count > 10 次).这个中的 undef $w 是取消掉这种 watcher 的方法.

复制代码 代码如下:
#!/usr/bin/perl
use strict;
use AnyEvent;

my $cv = AnyEvent->condvar;

my $count = 0;
my $w; $w = AnyEvent->timer(
after => 5,
interval => 2,
cb => sub {
$count++;
warn "这是第 $count 次调用";
if ($count >= 10) {
undef $w;
}
}
);
$cv->recv;

I/O WATCHERS

基本语法

复制代码 代码如下:
my $fh = ....; # 打开一个句柄

my $io; $io = AnyEvent->io(
fh => $fh, # 上面打开的句柄,也可以是标准输入和输出
poll => "w", # 这个地方可以选择 r 和 w 来表示读和写的 IO 事件
cb => sub {
syswrite( $fh, "写入的内容" );
undef $io;
}
);

使用实例:

下面的例子,是使用 io 监控到可以读,就调用 cb 的函数,直接读文件 test.txt,每次一个字节,直到读完这个文件就通过 undef 消掉这个事件.

复制代码 代码如下:
#!/usr/bin/perl
use strict;
use AnyEvent;

my $cv = AnyEvent->condvar;

open my $fh, "<test.txt" or die "不能打开文件句柄 $!";
my $io; $io = AnyEvent->io(
fh => $fh,
poll => "r",
cb => sub {
my $len = sysread( $fh, my $buf, 1 );
if ($len > 0) {
print "read '$buf'\n";
}
else {
undef $io;
die "读出错: $!";
}
});

$cv->recv;

IDLE WATCHERS

基本语法

复制代码 代码如下:
my $w = AnyEvent->idle (cb => sub { ... });

使用实例:

下面的例子,当整个程序中,没有其它事件在运行时,就会运行 idle .它就是当其它事件都在等待和空着的时候,所调用的.

复制代码 代码如下:
#!/usr/bin/perl
use strict;
use AnyEvent;

my $cv = AnyEvent->condvar;

my $t; $t = AnyEvent->timer(
after => 1,
interval => 1,
cb => sub { print time()."\n" }
);

my $w; $w = AnyEvent->idle(
cb => sub {
warn "idle";
# undef $w;
}
);

$cv->recv;

SIGNAL WATCHERS

基本语法如下,就是当接收到 POSIX signal 的时候,运行 callback 中的事件.

复制代码 代码如下:
my $w = AnyEvent->signal (signal => "TERM", cb => sub { ... });

CHILD PROCRSS WATCHERS

基本语法如下

复制代码 代码如下:
# child process exit
my $w = AnyEvent->child (pid => $pid, cb => sub {
my ($pid, $status) = @_;
...
});

条件变量(多个条件时)

这个是 AnyEvent 学习上面几种事件监控后必须要了解的.大家都见到上面有 AnyEvent->condvar; 和 $cv->recv这二个,condvar 是 condition variable 的简写.是指当什么样的条件成立时的变量

其实就是条件,当达到什么条件时退出事件循环.所以 AnyEvent 中没有传统事件中的 loop 函数.所以使用条件变量就相当于让事件这个转起来.

基本的 $cv->recv 是和 $cv->send 成对出现的,当事件调用 send 时,就一定要有 recv 收到这个调用,才会退出事件.

下面的 $cv->begin 和 $cv->end 也基本是这个意思.send 是单个条件.begin 和 end 是多个条件成立时退出,换个语来讲,就是这些事件都成对的完成后,才退出事件.

复制代码 代码如下:
#!/usr/bin/perl
use strict;
use AnyEvent;

my $cv = AnyEvent->condvar( cb => sub {
warn "调用结束";
});

for my $i (1..10) {
$cv->begin;
my $w; $w = AnyEvent->timer(after => $i, cb => sub {
warn "finished timer $i";
undef $w;
$cv->end;
});
}

$cv->recv;

默认的 condvar 会对事件建一个条件为假的变量,所以直接有 send 和 begin send 之类才会变成真,然后退出事件循环.可以给这个地方看成一个信号量来理解就好了.y
如果条件不成立,在 AnyEvent 中事件会一直 loop .所以上面的例子中没有 send .

有关 AnyEvent 其它,大家入门后可以玩玩象 AnyEvent::HTTP,twiggy 之类.看看这些应用和项目.

另外,在 AnyEvent 中我们常常使用 EV .他是一个 C 的 libev 的 Perl 接口,有非常高的性能.看完上面,在看看下面 EV 的使用,非常容易吧,基本不变.只是没出现条件变量,
使用的传统的 EV::loop; 来使这个运行起来.
复制代码 代码如下:
use EV;

# TIMERS

my $w = EV::timer 2, 0, sub {
warn "is called after 2s";
};

my $w = EV::timer 2, 2, sub {
warn "is called roughly every 2s (repeat = 2)";
};

undef $w; # destroy event watcher again

my $w = EV::periodic 0, 60, 0, sub {
warn "is called every minute, on the minute, exactly";
};

# IO

my $w = EV::io *STDIN, EV::READ, sub {
my ($w, $revents) = @_; # all callbacks receive the watcher and event mask
warn "stdin is readable, you entered: ", <STDIN>;
};

# SIGNALS

my $w = EV::signal 'QUIT', sub {
warn "sigquit received\n";
};

# CHILD/PID STATUS CHANGES

my $w = EV::child 666, 0, sub {
my ($w, $revents) = @_;
my $status = $w->rstatus;
};

# STAT CHANGES
my $w = EV::stat "/etc/passwd", 10, sub {
my ($w, $revents) = @_;
warn $w->path, " has changed somehow.\n";
};

# MAINLOOP
EV::loop; # loop until EV::unloop is called or all watchers stop
EV::loop EV::LOOP_ONESHOT; # block until at least one event could be handled
EV::loop EV::LOOP_NONBLOCK; # try to handle same events, but do not block

注:本文中大部分内容来自日本的@lestrrat


  • 上一条:
    Lua脚本获取喜马拉雅MP3音频地址
    下一条:
    Ruby最简单的消息服务器代码
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 2024.07.09日OpenAI将终止对中国等国家和地区API服务(0个评论)
    • 2024/6/9最新免费公益节点SSR/V2ray/Shadowrocket/Clash节点分享|科学上网|免费梯子(1个评论)
    • 国外服务器实现api.openai.com反代nginx配置(0个评论)
    • 2024/4/28最新免费公益节点SSR/V2ray/Shadowrocket/Clash节点分享|科学上网|免费梯子(1个评论)
    • 近期文章
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-07
    • 2017-08
    • 2017-09
    • 2018-01
    • 2018-07
    • 2018-08
    • 2018-09
    • 2018-12
    • 2019-01
    • 2019-02
    • 2019-03
    • 2019-04
    • 2019-05
    • 2019-06
    • 2019-07
    • 2019-08
    • 2019-09
    • 2019-10
    • 2019-11
    • 2019-12
    • 2020-01
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-09
    • 2020-10
    • 2020-11
    • 2021-04
    • 2021-05
    • 2021-06
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-03
    • 2022-04
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-08
    • 2023-09
    • 2023-10
    • 2023-12
    • 2024-02
    • 2024-04
    • 2024-05
    • 2024-06
    • 2025-02
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客