标题 | perl anyevent简单介绍和入门知识 |
内容 | 什么是面向事件的编程(事件驱动的编程): 编程中所有的程序是由事件决定 – 可以是由用户操作(键盘,鼠标),也可以是由其他程序和流的到达或者操作系统事件(如网络数据包到达)来触发执行. 面向事件编程可以也被定义为,写一个计算机程序,在其中的代码(通常程序的功能的头部)被明确分配应用程序的主回路,其代码本身由两部分组成方法:事件和事件处理的代码。 面向事件的编程通常被应用在三种情况下: 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 |
随便看 |
|
在线学习网考试资料包含高考、自考、专升本考试、人事考试、公务员考试、大学生村官考试、特岗教师招聘考试、事业单位招聘考试、企业人才招聘、银行招聘、教师招聘、农村信用社招聘、各类资格证书考试等各类考试资料。