As POE seems to be very popular these days I wanted to share an alternative way of handling non-blocking I/O (and other events). For this I include a simple made up example, where I will show how to wait for a filehandle "readable" event and wait for a child process to finish.
But first a quick overview/introduction to AnyEvent:
AnyEvent provides us with 'watchers', which watch out for events. Events like a filehandle becoming readable or writable, a timer that reaches his timeout, a signal or a condition becoming true.
To handle all these events AnyEvent needs an event loop. The interesting thing here is, that AnyEvent can use other event loops, like the one provided by Glib, which would allow easy integration with Gtk2 programs. Aside from that AnyEvent knows how to interface with the event loops of the Event and EV module, Tk and even Coro. For the case that none of these event loops is either loaded or their module installed on the system it comes with it's own pure Perl implementation.
The major advantage comes in when you write a module and you need to wait for I/O events or need timers: you don't need to decide which event loop to use or even come up with your own select() implementation. If your module uses AnyEvent it can be used in POE, IO::Async, Gtk2, Tk, Coro, and other modules that also use AnyEvent.
Now a simple example where I commented the most interesting parts:#!/opt/perl/bin/perl use strict; use AnyEvent; use POSIX; use IO::Handle; use Time::HiRes qw/usleep/; pipe my $par, my $chld; $par->autoflush (1); $chld->autoflush (1); my $pid = fork; defined $pid or die "fork failed: $!"; if ($pid) { # parent: # first we create a condition variable, which allows # us to wait for a 'condition' to become true. my $cvar = AnyEvent->condvar; # then we setup a watcher which will watch for the 'readable' # event for the parent end of the pipe. The callback we # pass will be executed when the filehandle becomes readable. my $read_watcher = AnyEvent->io (fh => $par, poll => 'r', cb => sub + { my $r = sysread $par, my $data, 1024; if (not defined $r) { $! == EAGAIN and return; die "sysread failed: $!"; } else { print "Data from child: [\n$data]\n"; } }); # after that a child watcher will be installed, where we wait # for the child to terminate. (AnyEvent installs a SIGCHLD handler # for us here). my $child_watcher = AnyEvent->child (pid => $pid, cb => sub { print "Child terminated\n"; # when the child terminated we are finished, and the broadcast # method will let the call to 'wait' below return. $cvar->broadcast; }); # here we start to wait for the 'broadcast' in the child # watcher. Under the hood AnyEvent starts one of the available # event loops for us (might be Glib, Event, EV, Tk or even it's # own pure Perl implementation via select(), depending on what is # available or loaded). $cvar->wait; } else { # child: my $cnt = 0; while (1) { usleep ((int rand (500000)) + 100000); syswrite $chld, "iteration count: ".++$cnt."\n" or die "write not successful: $!"; if ($cnt > 10) { exit 0 } } }
Instead of calling the wait method there you could also start an event loop explicitly. For example if you would like to use the EV module you could use the loop and unloop functions instead of wait and broadcast:
use EV; use AnyEvent; # ... my $child_watcher = AnyEvent->child (pid => $pid, cb => sub { print "Child terminated\n"; EV::unloop; }); EV::loop;
Some links of the modules noticed:
In reply to AnyEvent for I/O events by elmex
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |