AnyEvent
view release on metacpan or search on metacpan
lib/AnyEvent/Intro.pod view on Meta::CPAN
You can pass any number of arguments to C<send>, and every subsequent
call to C<recv> will return them.
=head2 The "main loop"
Most event-based frameworks have something called a "main loop" or "event
loop run function" or something similar.
Just like in C<recv> AnyEvent, these functions need to be called
eventually so that your event loop has a chance of actually looking for
the events you are interested in.
For example, in a L<Gtk2> program, the above example could also be written
like this:
use Gtk2 -init;
use AnyEvent;
############################################
# create a window and some label
my $window = new Gtk2::Window "toplevel";
$window->add (my $label = new Gtk2::Label "soon replaced by name");
$window->show_all;
############################################
# do our AnyEvent stuff
$| = 1; print "enter your name> ";
my $wait_for_input = AnyEvent->io (
fh => \*STDIN, poll => "r",
cb => sub {
# set the label
$label->set_text (scalar <STDIN>);
print "enter another name> ";
}
);
############################################
# Now enter Gtk2's event loop
main Gtk2;
No condition variable anywhere in sight - instead, we just read a line
from STDIN and replace the text in the label. In fact, since nobody
C<undef>s C<$wait_for_input> you can enter multiple lines.
Instead of waiting for a condition variable, the program enters the Gtk2
main loop by calling C<< Gtk2->main >>, which will block the program and
wait for events to arrive.
This also shows that AnyEvent is quite flexible - you didn't have to do
anything to make the AnyEvent watcher use Gtk2 (actually Glib) - it just
worked.
Admittedly, the example is a bit silly - who would want to read names
from standard input in a Gtk+ application? But imagine that instead of
doing that, you make an HTTP request in the background and display its
results. In fact, with event-based programming you can make many
HTTP requests in parallel in your program and still provide feedback to
the user and stay interactive.
And in the next part you will see how to do just that - by implementing an
HTTP request, on our own, with the utility modules AnyEvent comes with.
Before that, however, let's briefly look at how you would write your
program using only AnyEvent, without ever calling some other event
loop's run function.
In the example using condition variables, we used those to start waiting
for events, and in fact, condition variables are the solution:
my $quit_program = AnyEvent->condvar;
# create AnyEvent watchers (or not) here
$quit_program->recv;
If any of your watcher callbacks decide to quit (this is often
called an "unloop" in other frameworks), they can just call C<<
$quit_program->send >>. Of course, they could also decide not to and
call C<exit> instead, or they could decide never to quit (e.g. in a
long-running daemon program).
If you don't need some clean quit functionality and just want to run the
event loop, you can do this:
AnyEvent->condvar->recv;
And this is, in fact, the closest to the idea of a main loop run
function that AnyEvent offers.
=head2 Timers and other event sources
So far, we have used only I/O watchers. These are useful mainly to find
out whether a socket has data to read, or space to write more data. On sane
operating systems this also works for console windows/terminals (typically
on standard input), serial lines, all sorts of other devices, basically
almost everything that has a file descriptor but isn't a file itself. (As
usual, "sane" excludes windows - on that platform you would need different
functions for all of these, complicating code immensely - think "socket
only" on windows).
However, I/O is not everything - the second most important event source is
the clock. For example when doing an HTTP request you might want to time
out when the server doesn't answer within some predefined amount of time.
In AnyEvent, timer event watchers are created by calling the C<<
AnyEvent->timer >> method:
use AnyEvent;
my $cv = AnyEvent->condvar;
my $wait_one_and_a_half_seconds = AnyEvent->timer (
after => 1.5, # after how many seconds to invoke the cb?
cb => sub { # the callback to invoke
$cv->send;
lib/AnyEvent/Intro.pod view on Meta::CPAN
poll => "r",
There is a trick here, however: the read watcher isn't stored in a global
variable, but in a local one - if the callback returns, it would normally
destroy the variable and its contents, which would in turn unregister our
watcher.
To avoid that, we refer to the watcher variable in the watcher callback.
This means that, when the C<tcp_connect> callback returns, perl thinks
(quite correctly) that the read watcher is still in use - namely inside
the inner callback - and thus keeps it alive even if nothing else in the
program refers to it anymore (it is much like Baron Münchhausen keeping
himself from dying by pulling himself out of a swamp).
The trick, however, is that instead of:
my $read_watcher = AnyEvent->io (...
The program does:
my $read_watcher; $read_watcher = AnyEvent->io (...
The reason for this is a quirk in the way Perl works: variable names
declared with C<my> are only visible in the I<next> statement. If the
whole C<< AnyEvent->io >> call, including the callback, would be done in
a single statement, the callback could not refer to the C<$read_watcher>
variable to C<undef>ine it, so it is done in two statements.
Whether you'd want to format it like this is of course a matter of style.
This way emphasizes that the declaration and assignment really are one
logical statement.
The callback itself calls C<sysread> for as many times as necessary, until
C<sysread> returns either an error or end-of-file:
cb => sub {
my $len = sysread $fh, $response, 1024, length $response;
if ($len <= 0) {
Note that C<sysread> has the ability to append data it reads to a scalar
if we specify an offset, a feature which we make use of in this example.
When C<sysread> indicates we are done, the callback C<undef>ines
the watcher and then C<send>s the response data to the condition
variable. All this has the following effects:
Undefining the watcher destroys it, as our callback was the only one still
having a reference to it. When the watcher gets destroyed, it destroys the
callback, which in turn means the C<$fh> handle is no longer used, so that
gets destroyed as well. The result is that all resources will be nicely
cleaned up by perl for us.
=head3 Using the finger client
Now, we could probably write the same finger client in a simpler way if
we used C<IO::Socket::INET>, ignored the problem of multiple hosts and
ignored IPv6 and a few other things that C<tcp_connect> handles for us.
But the main advantage is that we can not only run this finger function in
the background, we even can run multiple sessions in parallel, like this:
my $f1 = finger "kuriyama", "freebsd.org";
my $f2 = finger "icculus?listarchives=1", "icculus.org";
my $f3 = finger "mikachu", "icculus.org";
print "kuriyama's gpg key\n" , $f1->recv, "\n";
print "icculus' plan archive\n" , $f2->recv, "\n";
print "mikachu's plan zomgn\n" , $f3->recv, "\n";
It doesn't look like it, but in fact all three requests run in
parallel. The code waits for the first finger request to finish first, but
that doesn't keep it from executing them parallel: when the first C<recv>
call sees that the data isn't ready yet, it serves events for all three
requests automatically, until the first request has finished.
The second C<recv> call might either find the data is already there, or it
will continue handling events until that is the case, and so on.
By taking advantage of network latencies, which allows us to serve other
requests and events while we wait for an event on one socket, the overall
time to do these three requests will be greatly reduced, typically all
three are done in the same time as the slowest of the three requests.
By the way, you do not actually have to wait in the C<recv> method on an
AnyEvent condition variable - after all, waiting is evil - you can also
register a callback:
$f1->cb (sub {
my $response = shift->recv;
# ...
});
The callback will be invoked only when C<send> is called. In fact,
instead of returning a condition variable you could also pass a third
parameter to your finger function, the callback to invoke with the
response:
sub finger($$$) {
my ($user, $host, $cb) = @_;
How you implement it is a matter of taste - if you expect your function to
be used mainly in an event-based program you would normally prefer to pass
a callback directly. If you write a module and expect your users to use
it "synchronously" often (for example, a simple http-get script would not
really care much for events), then you would use a condition variable and
tell them "simply C<< ->recv >> the data".
=head3 Problems with the implementation and how to fix them
To make this example more real-world-ready, we would not only implement
some write buffering (for the paranoid, or maybe denial-of-service aware
security expert), but we would also have to handle timeouts and maybe
protocol errors.
Doing this quickly gets unwieldy, which is why we introduce
L<AnyEvent::Handle> in the next section, which takes care of all these
details for you and lets you concentrate on the actual protocol.
=head2 Implementing simple HTTP and HTTPS GET requests with AnyEvent::Handle
( run in 0.810 second using v1.01-cache-2.11-cpan-f56aa216473 )