AnyEvent
view release on metacpan or search on metacpan
These let you safely fork new subprocesses, either locally or
remotely (e.g.v ia ssh), using some RPC protocol or not, without the
limitations normally imposed by fork (AnyEvent works fine for
example). Dynamically-resized worker pools are obviously included as
well.
And they are quite tiny and fast as well - "abusing" AnyEvent::Fork
just to exec external programs can easily beat using "fork" and
"exec" (or even "system") in most programs.
AnyEvent::Filesys::Notify
AnyEvent is good for non-blocking stuff, but it can't detect file or
path changes (e.g. "watch this directory for new files", "watch this
file for changes"). The AnyEvent::Filesys::Notify module promises to
do just that in a portbale fashion, supporting inotify on GNU/Linux
and some weird, without doubt broken, stuff on OS X to monitor
files. It can fall back to blocking scans at regular intervals
transparently on other platforms, so it's about as portable as it
gets.
(I haven't used it myself, but it seems the biggest problem with it
is it quite bad performance).
AnyEvent::DBI
Executes DBI requests asynchronously in a proxy process for you,
notifying you in an event-based way when the operation is finished.
AnyEvent::FastPing
The fastest ping in the west.
Coro
Has special support for AnyEvent via Coro::AnyEvent, which allows
you to simply invert the flow control - don't call us, we will call
you:
async {
Coro::AnyEvent::sleep 5; # creates a 5s timer and waits for it
print "5 seconds later!\n";
Coro::AnyEvent::readable *STDIN; # uses an I/O watcher
my $line = <STDIN>; # works for ttys
AnyEvent::HTTP::http_get "url", Coro::rouse_cb;
my ($body, $hdr) = Coro::rouse_wait;
};
SIMPLIFIED AE API
Starting with version 5.0, AnyEvent officially supports a second, much
simpler, API that is designed to reduce the calling, typing and memory
overhead by using function call syntax and a fixed number of parameters.
See the AE manpage for details.
ERROR AND EXCEPTION HANDLING
In general, AnyEvent does not do any error handling - it relies on the
caller to do that if required. The AnyEvent::Strict module (see also the
"PERL_ANYEVENT_STRICT" environment variable, below) provides strict
checking of all AnyEvent methods, however, which is highly useful during
development.
As for exception handling (i.e. runtime errors and exceptions thrown
while executing a callback), this is not only highly event-loop
specific, but also not in any way wrapped by this module, as this is the
job of the main program.
The pure perl event loop simply re-throws the exception (usually within
"condvar->recv"), the Event and EV modules call "$Event/EV::DIED->()",
Glib uses "install_exception_handler" and so on.
ENVIRONMENT VARIABLES
AnyEvent supports a number of environment variables that tune the
runtime behaviour. They are usually evaluated when AnyEvent is loaded,
initialised, or a submodule that uses them is loaded. Many of them also
cause AnyEvent to load additional modules - for example,
"PERL_ANYEVENT_DEBUG_WRAP" causes the AnyEvent::Debug module to be
loaded.
All the environment variables documented here start with
"PERL_ANYEVENT_", which is what AnyEvent considers its own namespace.
Other modules are encouraged (but by no means required) to use
"PERL_ANYEVENT_SUBMODULE" if they have registered the
AnyEvent::Submodule namespace on CPAN, for any submodule. For example,
AnyEvent::HTTP could be expected to use "PERL_ANYEVENT_HTTP_PROXY" (it
should not access env variables starting with "AE_", see below).
All variables can also be set via the "AE_" prefix, that is, instead of
setting "PERL_ANYEVENT_VERBOSE" you can also set "AE_VERBOSE". In case
there is a clash btween anyevent and another program that uses
"AE_something" you can set the corresponding "PERL_ANYEVENT_something"
variable to the empty string, as those variables take precedence.
When AnyEvent is first loaded, it copies all "AE_xxx" env variables to
their "PERL_ANYEVENT_xxx" counterpart unless that variable already
exists. If taint mode is on, then AnyEvent will remove *all* environment
variables starting with "PERL_ANYEVENT_" from %ENV (or replace them with
"undef" or the empty string, if the corresaponding "AE_" variable is
set).
The exact algorithm is currently:
1. if taint mode enabled, delete all PERL_ANYEVENT_xyz variables from %ENV
2. copy over AE_xyz to PERL_ANYEVENT_xyz unless the latter alraedy exists
3. if taint mode enabled, set all PERL_ANYEVENT_xyz variables to undef.
This ensures that child processes will not see the "AE_" variables.
The following environment variables are currently known to AnyEvent:
"PERL_ANYEVENT_VERBOSE"
By default, AnyEvent will log messages with loglevel 4 ("error") or
higher (see AnyEvent::Log). You can set this environment variable to
a numerical loglevel to make AnyEvent more (or less) talkative.
If you want to do more than just set the global logging level you
should have a look at "PERL_ANYEVENT_LOG", which allows much more
complex specifications.
When set to 0 ("off"), then no messages whatsoever will be logged
with everything else at defaults.
When set to 5 or higher ("warn"), AnyEvent warns about unexpected
conditions, such as not being able to load the event model specified
by "PERL_ANYEVENT_MODEL", or a guard callback throwing an exception
- this is the minimum recommended level for use during development.
When set to 7 or higher (info), AnyEvent reports which event model
it chooses.
When set to 8 or higher (debug), then AnyEvent will report extra
information on which optional modules it loads and how it implements
certain features.
"PERL_ANYEVENT_LOG"
Accepts rather complex logging specifications. For example, you
could log all "debug" messages of some module to stderr, warnings
and above to stderr, and errors and above to syslog, with:
PERL_ANYEVENT_LOG=Some::Module=debug,+log:filter=warn,+%syslog:%syslog=error,syslog
For the rather extensive details, see AnyEvent::Log.
This variable is evaluated when AnyEvent (or AnyEvent::Log) is
loaded, so will take effect even before AnyEvent has initialised
itself.
Note that specifying this environment variable causes the
AnyEvent::Log module to be loaded, while "PERL_ANYEVENT_VERBOSE"
does not, so only using the latter saves a few hundred kB of memory
unless a module explicitly needs the extra features of
AnyEvent::Log.
"PERL_ANYEVENT_STRICT"
AnyEvent does not do much argument checking by default, as thorough
argument checking is very costly. Setting this variable to a true
value will cause AnyEvent to load "AnyEvent::Strict" and then to
thoroughly check the arguments passed to most method calls. If it
finds any problems, it will croak.
In other words, enables "strict" mode.
Unlike "use strict" (or its modern cousin, "use common::sense", it
is definitely recommended to keep it off in production. Keeping
"PERL_ANYEVENT_STRICT=1" in your environment while developing
programs can be very useful, however.
"PERL_ANYEVENT_DEBUG_SHELL"
If this env variable is nonempty, then its contents will be
interpreted by "AnyEvent::Socket::parse_hostport" and
"AnyEvent::Debug::shell" (after replacing every occurance of $$ by
the process pid). The shell object is saved in
$AnyEvent::Debug::SHELL.
This happens when the first watcher is created.
For example, to bind a debug shell on a unix domain socket in
/tmp/debug<pid>.sock, you could use this:
PERL_ANYEVENT_DEBUG_SHELL=/tmp/debug\$\$.sock perlprog
# connect with e.g.: socat readline /tmp/debug123.sock
Or to bind to tcp port 4545 on localhost:
PERL_ANYEVENT_DEBUG_SHELL=127.0.0.1:4545 perlprog
Net::FCP, and it works as simple as in any other, similar, module.
More complicated is "txn_client_get": It only creates a transaction
(completion, result, ...) object and initiates the transaction.
my $txn = bless { }, Net::FCP::Txn::;
It also creates a condition variable that is used to signal the
completion of the request:
$txn->{finished} = AnyAvent->condvar;
It then creates a socket in non-blocking mode.
socket $txn->{fh}, ...;
fcntl $txn->{fh}, F_SETFL, O_NONBLOCK;
connect $txn->{fh}, ...
and !$!{EWOULDBLOCK}
and !$!{EINPROGRESS}
and Carp::croak "unable to connect: $!\n";
Then it creates a write-watcher which gets called whenever an error
occurs or the connection succeeds:
$txn->{w} = AnyEvent->io (fh => $txn->{fh}, poll => 'w', cb => sub { $txn->fh_ready_w });
And returns this transaction object. The "fh_ready_w" callback gets
called as soon as the event loop detects that the socket is ready for
writing.
The "fh_ready_w" method makes the socket blocking again, writes the
request data and replaces the watcher by a read watcher (waiting for
reply data). The actual code is more complicated, but that doesn't
matter for this example:
fcntl $txn->{fh}, F_SETFL, 0;
syswrite $txn->{fh}, $txn->{request}
or die "connection or write error";
$txn->{w} = AnyEvent->io (fh => $txn->{fh}, poll => 'r', cb => sub { $txn->fh_ready_r });
Again, "fh_ready_r" waits till all data has arrived, and then stores the
result and signals any possible waiters that the request has finished:
sysread $txn->{fh}, $txn->{buf}, length $txn->{$buf};
if (end-of-file or data complete) {
$txn->{result} = $txn->{buf};
$txn->{finished}->send;
$txb->{cb}->($txn) of $txn->{cb}; # also call callback
}
The "result" method, finally, just waits for the finished signal (if the
request was already finished, it doesn't wait, of course, and returns
the data:
$txn->{finished}->recv;
return $txn->{result};
The actual code goes further and collects all errors ("die"s,
exceptions) that occurred during request processing. The "result" method
detects whether an exception as thrown (it is stored inside the $txn
object) and just throws the exception, which means connection errors and
other problems get reported to the code that tries to use the result,
not in a random callback.
All of this enables the following usage styles:
1. Blocking:
my $data = $fcp->client_get ($url);
2. Blocking, but running in parallel:
my @datas = map $_->result,
map $fcp->txn_client_get ($_),
@urls;
Both blocking examples work without the module user having to know
anything about events.
3a. Event-based in a main program, using any supported event module:
use EV;
$fcp->txn_client_get ($url)->cb (sub {
my $txn = shift;
my $data = $txn->result;
...
});
EV::run;
3b. The module user could use AnyEvent, too:
use AnyEvent;
my $quit = AnyEvent->condvar;
$fcp->txn_client_get ($url)->cb (sub {
...
$quit->send;
});
$quit->recv;
BENCHMARKS
To give you an idea of the performance and overheads that AnyEvent adds
over the event loops themselves and to give you an impression of the
speed of various event loops I prepared some benchmarks.
BENCHMARKING ANYEVENT OVERHEAD
Here is a benchmark of various supported event models used natively and
through AnyEvent. The benchmark creates a lot of timers (with a zero
timeout) and I/O watchers (watching STDOUT, a pty, to become writable,
which it is), lets them fire exactly once and destroys them again.
Source code for this benchmark is found as eg/bench in the AnyEvent
distribution. It uses the AE interface, which makes a real difference
for the EV and Perl backends only.
Explanation of the columns
*watcher* is the number of event watchers created/destroyed. Since
( run in 0.626 second using v1.01-cache-2.11-cpan-39bf76dae61 )