any event intro
DESCRIPTION
From Beijing Perl Workshop 2011 http://conference.perlchina.org/bjpw2011/TRANSCRIPT
AnyEvent介绍Achilles Xu
11年7月4日星期一
Contents简介
Hello World
Watcher
CondVar
参数传递
工具模块
封装
Bugs
11年7月4日星期一
丫是啥?
一个异步框架,支持多种底层驱动
EV, libevent, POE, Glib, QT, Tk
11年7月4日星期一
Hello Worlduse AnyEvent;
my $cv = AnyEvent->condvar;
my $w = AnyEvent->timer(
'after' => 5,
'cb' => sub {
print "hello world\n";
$cv->send;
}
);
$cv->recv;
11年7月4日星期一
元素介绍watcher
I/O
timer
signal
child process
idle
condvar
工具模块
AnyEvent::Handle
AnyEvent::DNS
AnyEvent::Socket
11年7月4日星期一
I/O Watcher use AnyEvent;
$| = 1; print "enter your name> ";
my $name;
my $wait_for_input = AnyEvent->io ( fh => \*STDIN, # which file handle to check poll => "r", # which event to wait for ("r"ead data) cb => sub { # what callback to execute $name = <STDIN>; # read it } );
# do something else here
11年7月4日星期一
Timer Watcher
my $once_per_second = AnyEvent->timer ( after => 0, # first invoke ASAP interval => 1, # then invoke every second cb => sub { # the callback to invoke print "hi\n"; }, );
11年7月4日星期一
Watcher变量的作用域
Watcher变量超出作用域以后,会被注销
11年7月4日星期一
Watcher变量的作用域use AnyEvent;
sub aaa {
my $w = AnyEvent->Timer(
after => 3,
interval => 5,
cb => sub { print "hello\n"; }
);
}
my $cv = AnyEvent->condvar;
aaa();
$cv->recv; # won't print hello every 5 seconds.11年7月4日星期一
Watcher变量的作用域use AnyEvent;
my $w; # 把Watcher变量存储在外层作用域
sub aaa {
$w = AnyEvent->Timer(
after => 3,
interval => 5,
cb => sub { print "hello\n"; }
);
}
my $cv = AnyEvent->condvar;
aaa();
$cv->recv; # will print hello every 5 seconds.
11年7月4日星期一
Watcher变量的作用域use AnyEvent;
sub aaa {
# 用闭包保存watcher变量
my $w; $w = AnyEvent->Timer(
after => 3,
interval => 5,
cb => sub { print "hello\n"; $w; }
);
}
my $cv = AnyEvent->condvar;
aaa();
$cv->recv; # will print hello every 5 seconds.
11年7月4日星期一
Watcher变量的作用域use AnyEvent;
sub aaa {
my $w; $w = AnyEvent->timer(
after => 5,
cb => sub {
print "hello\n";
undef $w;
});
}
aaa();
AnyEvent->condvar()->recv();
11年7月4日星期一
CondVar
启动main loop,类似POE::Kernal->run();
同步点控制,类似$thread->join();
“This module is an AnyEvent user, you need to make sure that you use and run a supported event loop.”
11年7月4日星期一
CondVaruse AnyEvent;
my $w = AnyEvent->timer(
after => 0,
interval => 5,
cb => sub {
print "hello\n";
}
);
my $cv = AnyEvent->condvar;
$cv->recv; # just like while (1) {...}
11年7月4日星期一
CondVaruse AnyEvent;
use AnyEvent::HTTP;
# 顺序执行一些操作...
my @cvs;
for (1 .. 5) {
my $cv = AnyEvent->condvar; # like thread id
push @cvs, $cv;
http_get("http://some_url", sub {
$cv->send; # like return in thread func
});
}
$_->recv for @cvs; # like $_->join for @threads;
# 继续顺序执行一些操作...
11年7月4日星期一
参数传递
闭包(closure)是唯一方式
PP(Par::Packer)打包时会产生很警告
perl -T
11年7月4日星期一
参数传递
use AnyEvent;
my $x = "Tom";
AnyEvent->timer(afer => 5, cb => sub {
print "hello $x";
}
11年7月4日星期一
工具模块use AnyEvent;
use AnyEvent::Handle; my $cv = AnyEvent->condvar; my $hdl; $hdl = new AnyEvent::Handle fh => \*STDIN, on_error => sub { my ($hdl, $fatal, $msg) = @_; warn "got error $msg\n"; $hdl->destroy; $cv->send; }; # send some request line $hdl->push_write ("getinfo\015\012"); # read the response line $hdl->push_read (line => sub { my ($hdl, $line) = @_; warn "got line <$line>\n"; $cv->send; }); $cv->recv;
11年7月4日星期一
工具模块use AnyEvent;
use AnyEvent::HTTP;
my $cv = AnyEvent->condvar;
http_get("http://www.sina.com.cn", # 不存在watcher作用域问题
sub {
my ($data, $headers) = @_;
print $headers->{Status}, "\n";
print $data, "\n";
$cv->send;
});
$cv->recv;
11年7月4日星期一
工具模块use AnyEvent; # not AE
# file handle or descriptor readable my $w = AE::io $fh, 0, sub { ... };
# one-shot or repeating timers my $w = AE::timer $seconds, 0, sub { ... }; # once my $w = AE::timer $seconds, $interval, sub { ... }; # repeated
print AE::now; # prints current event loop time print AE::time; # think Time::HiRes::time or simply CORE::time. my $cv = AE::cv;
11年7月4日星期一
封装
顺序完成几个步骤,然后调用传入的回调函数
并发做几件事,全部完成后调用传入的回调函数
以上二者结合
状态数据隐藏在封装函数的内部
适用于所有异步消息框架的封装
11年7月4日星期一
封装http_get_retry("http://www.sina.com.cn",
max_retries => 3,
sub {
my ($data, $headers) = @_;
if (defined $data) {
print "load ok";
} else {
print "try 3 times failed";
}
});
11年7月4日星期一
封装http_get_file("http://aaa.com/somefile.tar.gz",
"/data/files/somefile.tar.gz",
max_concurrent => 20,
sub {
my ($data, $headers) = @_;
if (defined $data) {
print "download ok";
} else {
print "some error happens: " . $headers->{Status};
}
});
11年7月4日星期一
封装
http_get( $url, sub { ... });
DNS Resolving
TCP Connecting
Sending Request
Reading Response
11年7月4日星期一
Bugs
多进程侦听socket
accept后使用push_read
rtimeout有时会瞬间出发
驱动:EV、PurePerl
单进程时不会发生
11年7月4日星期一
Bug's Solution
超时回调中做补差timer
*AE::now = sub { return AE::time; }
*AE::now = *AE::time doesn't work
11年7月4日星期一
谢谢
Questions?
11年7月4日星期一