Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Event-driven programming with Perl

Event-driven programming with Perl

My talk about doing event-driven programming with perl in OSDC.tw 2012.

#osdctw2012

Kang-min Liu

April 14, 2012
Tweet

More Decks by Kang-min Liu

Other Decks in Technology

Transcript

  1. In computer programming, event- driven programming or event-based programming is

    a programming paradigm in which the flow of the program is determined by events—e.g., sensor outputs or user actions (mouse clicks, key presses) or messages from other programs or threads. ref: wikipedia 12年4月14日星期六
  2. In computer programming, event- driven programming or event-based programming is

    a programming paradigm in which the flow of the program is determined by events—e.g., sensor outputs or user actions (mouse clicks, key presses) or messages from other programs or threads. ref: wikipedia 12年4月14日星期六
  3. Event Loop In Perl • Event • Event::Lib(libevent) • IO::Async

    • EV (libev) • Glib • Gtk • Tk • Prima • Net::IRC • Mojo::IOLoop • POE 12年4月14日星期六
  4. use Event::Lib; use POSIX qw/SIGINT/; $|=1; # autoflush STDOUT sub

    timer { my $event = shift; print localtime . "\r"; $event->add(1); } sub signal { my $event = shift; print "BYE BYE\n"; exit; } my $timer = timer_new(\&timer); my $signal = signal_new(SIGINT, \&signal); $timer->add(1); # triggered every second $signal->add; event_mainloop; 12年4月14日星期六
  5. use Event::Lib; use POSIX qw/SIGINT/; $|=1; # autoflush STDOUT sub

    timer { my $event = shift; print localtime . "\r"; $event->add(1); } sub signal { my $event = shift; print "BYE BYE\n"; exit; } my $timer = timer_new(\&timer); my $signal = signal_new(SIGINT, \&signal); $timer->add(1); # triggered every second $signal->add; event_mainloop; 12年4月14日星期六
  6. use Event::Lib; use POSIX qw/SIGINT/; $|=1; # autoflush STDOUT sub

    timer { my $event = shift; print localtime . "\r"; $event->add(1); } sub signal { my $event = shift; print "BYE BYE\n"; exit; } my $timer = timer_new(\&timer); my $signal = signal_new(SIGINT, \&signal); $timer->add(1); # triggered every second $signal->add; event_mainloop; Event 12年4月14日星期六
  7. use Event::Lib; use POSIX qw/SIGINT/; $|=1; # autoflush STDOUT sub

    timer { my $event = shift; print localtime . "\r"; $event->add(1); } sub signal { my $event = shift; print "BYE BYE\n"; exit; } my $timer = timer_new(\&timer); my $signal = signal_new(SIGINT, \&signal); $timer->add(1); # triggered every second $signal->add; event_mainloop; Handlers 12年4月14日星期六
  8. use Event::Lib; use POSIX qw/SIGINT/; $|=1; # autoflush STDOUT sub

    timer { my $event = shift; print localtime . "\r"; $event->add(1); } sub signal { my $event = shift; print "BYE BYE\n"; exit; } my $timer = timer_new(\&timer); my $signal = signal_new(SIGINT, \&signal); $timer->add(1); # triggered every second $signal->add; event_mainloop; ਐೖࣄ݅᫮ᅲ 12年4月14日星期六
  9. use Event::Lib; use POSIX qw/SIGINT/; $|=1; # autoflush STDOUT sub

    timer { my $event = shift; print localtime . "\r"; $event->add(1); } sub signal { my $event = shift; print "BYE BYE\n"; exit; } my $timer = timer_new(\&timer); my $signal = signal_new(SIGINT, \&signal); $timer->add(1); # triggered every second $signal->add; event_mainloop; 12年4月14日星期六
  10. use POE; $|=1; sub handler_tick { print localtime . "\r";

    $_[KERNEL]->alarm( 'tick' => time() + 1 ); } sub handler_start { $_[KERNEL]->sig('INT', 'handle_sigint'); $_[KERNEL]->alarm( 'tick', time() + 1 ); } sub handler_stop { print "\nBYE BYE\n"; } sub handle_sigint { $_[KERNEL]->stop; } POE::Session->create( inline_states => { _start => \&handler_start, _stop => \&handler_stop, tick => \&handler_tick, } ); POE::Kernel->run(); 12年4月14日星期六
  11. use POE; $|=1; sub handler_tick { print localtime . "\r";

    $_[KERNEL]->alarm( 'tick' => time() + 1 ); } sub handler_start { $_[KERNEL]->sig('INT', 'handle_sigint'); $_[KERNEL]->alarm( 'tick', time() + 1 ); } sub handler_stop { print "\nBYE BYE\n"; } sub handle_sigint { $_[KERNEL]->stop; } POE::Session->create( inline_states => { _start => \&handler_start, _stop => \&handler_stop, tick => \&handler_tick, } ); POE::Kernel->run(); 12年4月14日星期六
  12. use POE; $|=1; sub handler_tick { print localtime . "\r";

    $_[KERNEL]->alarm( 'tick' => time() + 1 ); } sub handler_start { $_[KERNEL]->sig('INT', 'handle_sigint'); $_[KERNEL]->alarm( 'tick', time() + 1 ); } sub handler_stop { print "\nBYE BYE\n"; } sub handle_sigint { $_[KERNEL]->stop; } POE::Session->create( inline_states => { _start => \&handler_start, _stop => \&handler_stop, tick => \&handler_tick, } ); POE::Kernel->run(); Event 12年4月14日星期六
  13. use POE; $|=1; sub handler_tick { print localtime . "\r";

    $_[KERNEL]->alarm( 'tick' => time() + 1 ); } sub handler_start { $_[KERNEL]->sig('INT', 'handle_sigint'); $_[KERNEL]->alarm( 'tick', time() + 1 ); } sub handler_stop { print "\nBYE BYE\n"; } sub handle_sigint { $_[KERNEL]->stop; } POE::Session->create( inline_states => { _start => \&handler_start, _stop => \&handler_stop, tick => \&handler_tick, } ); POE::Kernel->run(); Event Handlers 12年4月14日星期六
  14. use POE; $|=1; sub handler_tick { print localtime . "\r";

    $_[KERNEL]->alarm( 'tick' => time() + 1 ); } sub handler_start { $_[KERNEL]->sig('INT', 'handle_sigint'); $_[KERNEL]->alarm( 'tick', time() + 1 ); } sub handler_stop { print "\nBYE BYE\n"; } sub handle_sigint { $_[KERNEL]->stop; } POE::Session->create( inline_states => { _start => \&handler_start, _stop => \&handler_stop, tick => \&handler_tick, } ); POE::Kernel->run(); ਐೖࣄ݅᫮ᅲ 12年4月14日星期六
  15. AnyEvent • Marc Lehmann @schmorp • http://home.schmorp.de • libev /

    rxvt-unicode / deliantra / JSON::XS 12年4月14日星期六
  16. AnyEvent • Library for Event-based or asynchronous programming • ݱ༗

    Event loop తந৅૚ 12年4月14日星期六
  17. AnyEvent Event • AnyEvent ຊ਎ᔒ༗ Event model • ࢖༻ऀجຊ্୞႔ཧඇಉ㑊ᬓा •

    AnyEvent ࠶ሡඇಉ㑊ᬓ์ਐݱ੒ event loop ڈࣥߦ 12年4月14日星期六
  18. AnyEvent Watcher • io • timer • signal • child

    • idle • condvar 12年4月14日星期六
  19. my $t = AnyEvent->timer( after => 0, interval => 1,

    cb => sub { say localtime; } ); 12年4月14日星期六
  20. my $t = AnyEvent->timer( after => 0, interval => 1,

    cb => sub { say localtime; } ); Watcher 12年4月14日星期六
  21. my $t = AnyEvent->timer( after => 0, interval => 1,

    cb => sub { say localtime; } ); Watcher setInterval 12年4月14日星期六
  22. my $t = AnyEvent->timer( after => 0, interval => 1,

    cb => sub { say localtime; } ); ... undef $t; 12年4月14日星期六
  23. my $t = AnyEvent->timer( after => 0, interval => 1,

    cb => sub { say localtime; } ); ... undef $t; ෆཁ࠶㑌ඵҹ࣌ؒྃ 12年4月14日星期六
  24. my $t = AnyEvent->timer( after => 0, interval => 1,

    cb => sub { say localtime; } ); ... undef $t; ෆཁ࠶㑌ඵҹ࣌ؒྃ clearInterval 12年4月14日星期六
  25. my $w = AnyEvent->signal( signal => "TERM", cb => sub

    { ... } ); 12年4月14日星期六
  26. $SIG{TERM} = sub { do_this; }; $SIG{TERM} = sub {

    do_that; }; 12年4月14日星期六
  27. $SIG{TERM} = sub { do_this; }; $SIG{TERM} = sub {

    do_that; }; ☹ 12年4月14日星期六
  28. my $w = AnyEvent->signal( signal => "TERM", cb => sub

    { do_this } ); my $q = AnyEvent->signal( signal => "TERM", cb => sub { do_that } ); 12年4月14日星期六
  29. my $w = AnyEvent->signal( signal => "TERM", cb => sub

    { do_this } ); my $q = AnyEvent->signal( signal => "TERM", cb => sub { do_that } ); OK! 12年4月14日星期六
  30. my $w = AnyEvent->io( fh => $fh, poll => "r",

    cb => sub { ... } ); 12年4月14日星期六
  31. my $pid = fork; my $child_watcher; if ($pid) { $child_watcher

    = AnyEvent->child ( pid => $pid, cb => sub { my ($pid, $status) = @_; ... } ); } else { # child code } 12年4月14日星期六
  32. my $w = AnyEvent->idle( cb => sub { ... }

    ); 12年4月14日星期六
  33. use AnyEvent; $|=1; my $should_exit = AnyEvent->condvar; my $t =

    AnyEvent->timer( after => 0, interval => 1, cb => sub { print localtime."\r"; } ); my $s = AnyEvent->signal( signal => "INT", cb => sub { print "\na\BYE BYE\n"; $should_exit->send; } ); $should_exit->recv; 12年4月14日星期六
  34. use AnyEvent; $|=1; my $should_exit = AnyEvent->condvar; my $t =

    AnyEvent->timer( after => 0, interval => 1, cb => sub { print localtime."\r"; } ); my $s = AnyEvent->signal( signal => "INT", cb => sub { print "\na\BYE BYE\n"; $should_exit->send; } ); $should_exit->recv; 12年4月14日星期六
  35. use AnyEvent; $|=1; my $should_exit = AnyEvent->condvar; my $t =

    AnyEvent->timer( after => 0, interval => 1, cb => sub { print localtime."\r"; } ); my $s = AnyEvent->signal( signal => "INT", cb => sub { print "\na\BYE BYE\n"; $should_exit->send; } ); $should_exit->recv; Watcher 12年4月14日星期六
  36. use AnyEvent; $|=1; my $should_exit = AnyEvent->condvar; my $t =

    AnyEvent->timer( after => 0, interval => 1, cb => sub { print localtime."\r"; } ); my $s = AnyEvent->signal( signal => "INT", cb => sub { print "\na\BYE BYE\n"; $should_exit->send; } ); $should_exit->recv; Handler 12年4月14日星期六
  37. use AnyEvent; $|=1; my $should_exit = AnyEvent->condvar; my $t =

    AnyEvent->timer( after => 0, interval => 1, cb => sub { print localtime."\r"; } ); my $s = AnyEvent->signal( signal => "INT", cb => sub { print "\na\BYE BYE\n"; $should_exit->send; } ); $should_exit->recv; ਐೖࣄ݅᫮ᅲ 12年4月14日星期六
  38. AnyEvent Condvar $|=1; print "Enter your name> "; my $name

    = <STDIN>; print "Hello, $name\n"; 12年4月14日星期六
  39. AnyEvent Condvar $|=1; print "Enter your name> "; my $name

    = <STDIN>; print "Hello, $name\n"; IO block 12年4月14日星期六
  40. use AnyEvent; $|=1; my $name_ready = AE::cv; my $angel =

    AE::io \*STDIN, 0, sub { my $x = <STDIN>; $name_ready->send($x); }; print "Enter your name> "; my $name = $name_ready->recv; print "\nHello, $name\n"; 12年4月14日星期六
  41. use AnyEvent; $|=1; my $name_ready = AE::cv; my $angel =

    AE::io \*STDIN, 0, sub { my $x = <STDIN>; $name_ready->send($x); }; print "Enter your name> "; my $name = $name_ready->recv; print "\nHello, $name\n"; block 12年4月14日星期六
  42. use AnyEvent; $|=1; my $name_ready = AE::cv; my $angel =

    AE::io \*STDIN, 0, sub { my $x = <STDIN>; $name_ready->send($x); }; print "Enter your name> "; my $name = $name_ready->recv; print "\nHello, $name\n"; block 12年4月14日星期六
  43. use AnyEvent; $|=1; my $name_ready = AE::cv; my $angel =

    AE::io \*STDIN, 0, sub { my $x = <STDIN>; $name_ready->send($x); }; my $daemon = AE::timer 5, 5, sub { print "\n\nHurry up!!\nEnter your name> "; }; print "Enter your name> "; my $name = $name_ready->recv; print "\nHello, $name\n"; block 12年4月14日星期六
  44. use AnyEvent; $|=1; my $exit = AE::cv { print "gg\n"

    }; my $name_ready = AE::cv { my ($cv) = @_; print "\nHello, " . $cv->recv; $exit->send; }; my $angel = AE::io \*STDIN, 0, sub { my $x = <STDIN>; $name_ready->send($x); }; my $daemon = AE::timer 5, 5, sub { print "\n\nHurry up!!\nEnter your name> "; }; print "Enter your name> "; $exit->recv; 12年4月14日星期六
  45. use AnyEvent; $|=1; my $exit = AE::cv { print "gg\n"

    }; my $name_ready = AE::cv { my ($cv) = @_; print "\nHello, " . $cv->recv; $exit->send; }; my $angel = AE::io \*STDIN, 0, sub { my $x = <STDIN>; $name_ready->send($x); }; my $daemon = AE::timer 5, 5, sub { print "\n\nHurry up!!\nEnter your name> "; }; print "Enter your name> "; $exit->recv; 12年4月14日星期六
  46. use AnyEvent; $|=1; my $exit = AE::cv { print "gg\n"

    }; my $name_ready = AE::cv { my ($cv) = @_; print "\nHello, " . $cv->recv; $exit->send; }; my $angel = AE::io \*STDIN, 0, sub { my $x = <STDIN>; $name_ready->send($x); }; my $daemon = AE::timer 5, 5, sub { print "\n\nHurry up!!\nEnter your name> "; }; print "Enter your name> "; $exit->recv; 12年4月14日星期六
  47. use v5.14; use AnyEvent; my ($start, $working, $end); $start =

    AE::cv { say "START"; $working->send; }; $working = AE::cv { say "WORKING for 5s"; my $w; $w = AE::timer 5, 0, sub { say "DONE working."; $end->send; undef $w; } }; $end = AE::cv { say "END"; }; $start->send; $end->recv; 12年4月14日星期六
  48. use v5.14; use AnyEvent; my ($start, $working, $end); $start =

    AE::cv { say "START"; $working->send; }; $working = AE::cv { say "WORKING for 5s"; my $w; $w = AE::timer 5, 0, sub { say "DONE working."; $end->send; undef $w; } }; $end = AE::cv { say "END"; }; $start->send; $end->recv; 12年4月14日星期六
  49. use v5.14; use AnyEvent; my ($start, $working, $end); $start =

    AE::cv { say "START"; $working->send; }; $working = AE::cv { say "WORKING for 5s"; my $w; $w = AE::timer 5, 0, sub { say "DONE working."; $end->send; undef $w; } }; $end = AE::cv { say "END"; }; $start->send; $end->recv; State State Handlers 12年4月14日星期六
  50. use v5.14; use AnyEvent; my ($start, $working, $end); $start =

    AE::cv { say "START"; $working->send; }; $working = AE::cv { say "WORKING for 5s"; my $w; $w = AE::timer 5, 0, sub { say "DONE working."; $end->send; undef $w; } }; $end = AE::cv { say "END"; }; $start->send; $end->recv; State Transition 12年4月14日星期六
  51. use v5.14; use AnyEvent; my ($start, $working, $end); $start =

    AE::cv { say "START"; $working->send; }; $working = AE::cv { say "WORKING for 5s"; my $w; $w = AE::timer 5, 0, sub { say "DONE working."; $end->send; undef $w; } }; $end = AE::cv { say "END"; }; $start->send; $end->recv; ਐೖ ࣄ݅᫮ᅲ 12年4月14日星期六
  52. anyEvent::CondVar • $cv ~ mini event loop • $cv->send →

    $cv->recv • $cv->send → $cv callback • $cv->begin, $cv->end 12年4月14日星期六
  53. AnyEvent::HTTP sub parallel_get { my @urls = @_; my $all_done

    = AE::cv; for my $url (@urls) { $all_done->begin; my $t = time; http_get $url, sub { my ($data, $headers) = @_; ... $all_done->end; }; } $all_done->recv; ... } 12年4月14日星期六
  54. AnyEvent::DBI use AnyEvent::DBI; my $cv = AnyEvent->condvar; my $dbh =

    new AnyEvent::DBI "DBI:SQLite:dbname=test.db", "", ""; $dbh->exec("select * from orders where owner=?", "gugod", sub { my ($dbh, $rows, $rv) = @_; $#_ or die "failure: $@"; print "@$_\n" for @$rows; $cv->send; }); # asynchronously do sth. else here $cv->recv; 12年4月14日星期六
  55. AnyEvent::Socket tcp_connect "gameserver.deliantra.net", 13327, sub { my ($fh) = @_

    or die "gameserver.deliantra.net connect failed: $!"; # enjoy your filehandle ... }; 12年4月14日星期六
  56. AnyEvent::Socket tcp_server undef, 8888, sub { my ($fh, $host, $port)

    = @_; syswrite $fh, "The internet is full, $host: $port. Go away!\015\012"; }; 12年4月14日星期六
  57. AnyEvent::IRC my $c = AnyEvent->condvar; my $con = new AnyEvent::IRC::Connection;

    $con->connect ("irc.server.net", 6667); $con->reg_cb ( 'connect' => sub { my ($con) = @_; $con->send_msg (NICK => 'testbot'); $con->send_msg (USER => 'testbot', '*', '0', 'testbot'); }, 'irc_001' => sub { my ($con) = @_; print "$_[1]->{prefix} says I'm in the IRC: $_[1]->{params}->[-1]!\n"; $c->broadcast; } ); $c->wait; 12年4月14日星期六
  58. my $cl = AnyEvent::XMPP::Client->new(); $cl->set_accounts({ '[email protected]' => [ 'PASSWORD', 'talk.google.com',

    5223, { domain => 'gmail.com', old_style_ssl => 1 } ], '[email protected]' => [ 'PASSWORD', 'talk.google.com', 5223, { domain => 'gmail.com', old_style_ssl => 1 } ] }); $cl->reg_cb( message => sub { my ($client, $account, $message) = @_; $client->send_message("Nihao", $message->from, $account->jid); }, contact_request_subscribe => sub { my ($client, $account, $roster, $contact, $message) = @_; $contact->send_subscribed; }, disconnect => sub { my $client = shift; $client->update_connections; } ); $cl->start; 12年4月14日星期六
  59. AnyEvent::MP • Or “AEMP” • ଟߦఔؒ㘤ଉၚᬇ (Message Passing) • IPC,

    ୠՄލओػ • 㘤ଉ༗Ճີʢshared secretʣ • Erlang ෩ 12年4月14日星期六
  60. use AnyEvent; use AnyEvent::MP; use AnyEvent::MP::Global; configure nodeid => "eg_receiver",

    binds => ["*:4040"]; my $port = port; grp_reg eg_receivers => $port; rcv $port, test => sub { my ($data, $reply_port) = @_; print "Received data: " . $data . "\n"; }; AnyEvent->condvar->recv; aemp receiver 12年4月14日星期六
  61. aemp sender use AnyEvent; use AnyEvent::MP; use AnyEvent::MP::Global; configure nodeid

    => "eg_sender", seeds => ["*:4040"]; my $find_timer = AnyEvent->timer (after => 0, interval => 1, cb => sub { my $ports = grp_get "eg_receivers" or return; snd $_, test => time for @$ports; }); AnyEvent->condvar->recv; 12年4月14日星期六
  62. AnyEvent::Worker my $worker = AnyEvent::Worker->new( sub { my @args =

    @_; ... } ); $worker->do("foo", "bar"); 12年4月14日星期六
  63. AnyEvent::Worker # fork 4 worker processes # put them in

    to a round-robin queue my $workers = Data::RoundRobin->new( map { AnyEvent::Worker->new(sub { ... }) } 1..4 ); $workers->next->do("foo", "bar"); # worker 1 $workers->next->do("this", "that"); # worker 2 $workers->next->do("ok", "go"); # workes 3 ... 12年4月14日星期六
  64. • German • Redis/Hiredis • BitTorrent • CouchDB • Cron

    • TermKey • DNS • JSONRPC • Monitor • MSN • RabbitMQ • SMTP • Twitter • ZeroMQ • Memcached • Twiggy AnyEvent::* 12年4月14日星期六
  65. More or Less • AnyEvent ੋᙛԼओྲྀ • AnyEvent::Intro • condvar

    = Fascinating • AnyEvent::* ༗ڐଟሞ • github.com/CPAN-API/metacpan-web 12年4月14日星期六