AnyEvent
view release on metacpan or search on metacpan
Every call to "->begin" will increment a counter, and every call to
"->end" will decrement it. If the counter reaches 0 in "->end", the
(last) callback passed to "begin" will be executed, passing the
condvar as first argument. That callback is *supposed* to call
"->send", but that is not required. If no group callback was set,
"send" will be called without any arguments.
You can think of "$cv->send" giving you an OR condition (one call
sends), while "$cv->begin" and "$cv->end" giving you an AND
condition (all "begin" calls must be "end"'ed before the condvar
sends).
Let's start with a simple example: you have two I/O watchers (for
example, STDOUT and STDERR for a program), and you want to wait for
both streams to close before activating a condvar:
my $cv = AnyEvent->condvar;
$cv->begin; # first watcher
my $w1 = AnyEvent->io (fh => $fh1, cb => sub {
defined sysread $fh1, my $buf, 4096
or $cv->end;
});
$cv->begin; # second watcher
my $w2 = AnyEvent->io (fh => $fh2, cb => sub {
defined sysread $fh2, my $buf, 4096
or $cv->end;
});
$cv->recv;
This works because for every event source (EOF on file handle),
there is one call to "begin", so the condvar waits for all calls to
"end" before sending.
The ping example mentioned above is slightly more complicated, as
the there are results to be passed back, and the number of tasks
that are begun can potentially be zero:
my $cv = AnyEvent->condvar;
my %result;
$cv->begin (sub { shift->send (\%result) });
for my $host (@list_of_hosts) {
$cv->begin;
ping_host_then_call_callback $host, sub {
$result{$host} = ...;
$cv->end;
};
}
$cv->end;
...
my $results = $cv->recv;
This code fragment supposedly pings a number of hosts and calls
"send" after results for all then have have been gathered - in any
order. To achieve this, the code issues a call to "begin" when it
starts each ping request and calls "end" when it has received some
result for it. Since "begin" and "end" only maintain a counter, the
order in which results arrive is not relevant.
There is an additional bracketing call to "begin" and "end" outside
the loop, which serves two important purposes: first, it sets the
callback to be called once the counter reaches 0, and second, it
ensures that "send" is called even when "no" hosts are being pinged
(the loop doesn't execute once).
This is the general pattern when you "fan out" into multiple (but
potentially zero) subrequests: use an outer "begin"/"end" pair to
set the callback and ensure "end" is called at least once, and then,
for each subrequest you start, call "begin" and for each subrequest
you finish, call "end".
METHODS FOR CONSUMERS
These methods should only be used by the consuming side, i.e. the code
awaits the condition.
$cv->recv
Wait (blocking if necessary) until the "->send" or "->croak" methods
have been called on $cv, while servicing other watchers normally.
You can only wait once on a condition - additional calls are valid
but will return immediately.
If an error condition has been set by calling "->croak", then this
function will call "croak".
In list context, all parameters passed to "send" will be returned,
in scalar context only the first one will be returned.
Note that doing a blocking wait in a callback is not supported by
any event loop, that is, recursive invocation of a blocking "->recv"
is not allowed and the "recv" call will "croak" if such a condition
is detected. This requirement can be dropped by relying on
Coro::AnyEvent , which allows you to do a blocking "->recv" from any
thread that doesn't run the event loop itself. Coro::AnyEvent is
loaded automatically when Coro is used with AnyEvent, so code does
not need to do anything special to take advantage of that: any code
that would normally block your program because it calls "recv", be
executed in an "async" thread instead without blocking other
threads.
Not all event models support a blocking wait - some die in that case
(programs might want to do that to stay interactive), so *if you are
using this from a module, never require a blocking wait*. Instead,
let the caller decide whether the call will block or not (for
example, by coupling condition variables with some kind of request
results and supporting callbacks so the caller knows that getting
the result will not block, while still supporting blocking waits if
the caller so desires).
You can ensure that "->recv" never blocks by setting a callback and
only calling "->recv" from within that callback (or at a later
time). This will work even when the event loop does not support
blocking waits otherwise.
( run in 0.999 second using v1.01-cache-2.11-cpan-b16cb0d3907 )