IO-Lambda
view release on metacpan or search on metacpan
lib/IO/Lambda.pm view on Meta::CPAN
# whatever the remote returns
my $buf = '';
# readable registers another event to monitor -
# that $socket is readable. Note that we do not
# need to set the context again because when we get
# here, the engine knows what context this command
# took place in, and assumes the same context.
# Also note that socket won't be awaited for writable events
# anymore, and this code won't be executed for this $socket.
readable {
# This closure is executed when we can read.
# Read from the socket. sysread() returns number of
# bytes read. Zero means EOF, and undef means error, so
# we stop on these conditions.
# If we return without registering a follow-up
# handler, this return will be processed as the
# end of this sequence of events for whoever is
# waiting on us.
return $buf unless
sysread( $socket, $buf, 1024, length($buf));
# We're not done so we need to do this again.
# Note that the engine knows that it just
# called this closure because $socket was
# readable, so it can infer that it is supposed
# to set up a callback that will call this
# closure when $socket is next readable.
again;
}}}
}
# Fire up a single lambda and wait until it completes.
print http('www.perl.com')-> wait;
# Fire up a lambda that waits for two http requests in parallel.
# tails() can wait for more than one lambda
my @hosts = ('www.perl.com', 'www.google.com');
lambda {
context map { http($_) } @hosts;
# tails() asynchronously waits until all lambdas in the context
# are finished.
tails { print @_ }
}-> wait;
# crawl for all urls in parallel, but keep 10 parallel connections max
print par(10)-> wait(map { http($_) } @hosts);
# crawl for all urls sequentially
print mapcar( curry { http(shift) })-> wait(@hosts);
Note: C<io> and C<lambda> are synonyms - I personally prefer C<lambda> but some
find the word slightly inappropriate, hence C<io>. See however L<Higher-order
functions> to see why it is more C<lambda> than C<io>.
=head1 DESCRIPTION
This module is another attempt to fight the horrors of non-blocking I/O. It
tries to bring back the simplicity of the declarative programming style, that
is only available when one employs threads, coroutines, or co-processes.
Usually coding non-blocking I/O for single process, single thread programs
requires construction of state machines, often fairly complex, which fact
doesn't help the code clarity, and is the reason why the asynchronous I/O
programming is often considered 'messy'. Similar to the concept of monads in
functional languages, that enforce a certain order of execution over generally
orderless functions, C<IO::Lambda> allows writing I/O callbacks in a style that
resembles the good old sequential, declarative programming.
The manual begins with code examples, then proceeds to explaining basic
assumptions, then finally gets to the complex concepts, where the real fun
begins. You can skip directly there (L<Stream IO>, L<Higher-order functions>),
where the functional style mixes with I/O. If, on the contrary, you are
intimidated by the module's ambitions, you can skip to L<Simple use> for a more
gentle introduction. Those, who are interested how the module is different from
the other I/O frameworks, please continue reading.
=head2 Simple use
This section is for those who don't need all of the module's powerful
machinery. Simple callback-driven programming examples show how to use the
module for unsophisticated tasks, using concepts similar to the other I/O
frameworks. It is possible to use the module on this level only, however one
must be aware that by doing so, the real power of the higher-order abstraction
is not used.
C<IO::Lambda>, like all I/O multiplexing libraries, provides functions for
registering callbacks, that in turn are called when a timeout occurs, or when a
file handle is ready for reading and/or writing. See below code examples that
demonstrate how to program on this level of abstraction.
=over
=item Combination of two timeouts and an IO_READ event
use IO::Lambda qw(:constants);
my $obj = IO::Lambda-> new;
# Either 3 or time + 3 will do. See "Time" section for more info
$obj-> watch_timer( 3, sub { print "I've slept 3 seconds!\n" });
# I/O flags is a combination of IO_READ, IO_WRITE, and IO_EXCEPTION.
# Timeout is either 5 or time + 5, too.
$obj-> watch_io( IO_READ, \*STDIN, 5, sub {
my ( $self, $ok) = @_;
print $ok ?
"stdin is readable!\n" :
"stdin is not readable within 5 seconds\n";
});
# main event loop is stopped when there are no lambdas and no
# pending events
IO::Lambda::run;
=item Waiting for another lambda to complete
use IO::Lambda;
my $a = IO::Lambda-> new;
$a-> watch_timer( 3, sub { print "I've slept 3 seconds!\n" });
( run in 1.237 second using v1.01-cache-2.11-cpan-df04353d9ac )