IO::Lambda - non-blocking I/O in lambda style
The code below executes parallel HTTP requests
use strict; use IO::Lambda qw(:lambda); use IO::Socket::INET;
# create a lambda object sub http { my ( $host, $url) = @_;
my $socket = IO::Socket::INET-> new(
PeerAddr => $host,
PeerPort => 80
);
lambda {
context $socket;
write {
print $socket "GET $url HTTP/1.0\r\n\r\n";
my $buf = '';
read {
return $buf unless
sysread( $socket, $buf, 1024, length($buf));
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 lambda { context http( 'www.perl.com', '/'), http( 'www.google.com', '/'); tails { print @_; } }-> wait;
Note: io and lambda are synonyms - I personally prefer lambda but some
find the word slightly inappropriate, hence io.
This module is another attempt to fight the horrors of non-blocking I/O programming. It tries to bring back the simplicity of the declarative programming style, that is only otherwise 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 doesn't help the clarity of the code. Not unlike monads in functional languages, that enforce order of execution over generally orderless functions, this framework helps programmer to express the order of execution of I/O callbacks in a coding style that resembles sequential, declarative programming.
The manual begins with code examples, then explains basic assumptions, then finally gets of the complex concepts, where the real fun begins. You may skip directly there (Stream IO), where functional style mixes with I/O.
There are many async libraries readily available from CPAN. IO::Lambda is
yet another one. How is it different from the existing tools? Why using it? To
answer these questions, I need to show the evolution of async libraries, to
show how they grew from simple tools to more complex frameworks.
First, all async libraries are based on OS-level syscalls, like select,
poll, epoll, kqueue, and Win32::WaitForMultipleObjects. The first
layer of async libraries provides access to exactly these facilites: there are
IO::Select, IO::Epoll, IO::Kqueue etc. I won't go deepeer into
describing pros and contras for programming on this level, this should be more
or less obvious.
Perl modules of the next abstraction layer are often characterised by two
things: portability and event loops. While the first layer calls are seldom
portable, and have no event loops, the second layer modules strive to be
OS-independent, and use callbacks to ease the async IO programming. These
modules mostly populate the "asynchronous input-output programming frameworks"
niche in the perl world. The examples are many: IO::Events, EV,
AnyEvent, IO::NonBlocking, to name the few.
Finally, there's the third layer of complexity, which, before IO::Lambda,
had a single representative: POE (now, to the best of my knowledge,
IO::Async also falls in this category). Modules of the third layer are based
on concepts from the second, but introduce a tool to help with the programming
of complex protocols, something that isn't available in the second layer
modules: finite state machines. The FSMs machines reduce complexity when
programming, for example, intricate network protocols, that are best modelled
as a set of states. Modules from the second layer do not provide much help
here. Also, the third layer modules are agnostic of the event loop module: the
programmer is (almost) free to choose the event loop backend, such as Gtk,
Prima, or AnyEvent, depending on the nature of the task.
IO::Lambda also allows the programmer to build complex protocols, and is
also based on event loops, callbacks, and is portable. It differs from POE
in the way the FSMs are declared. Where POE requires an explicit switch from
one state to another, using (f.ex.) post or yield commands, IO::Lambda
incorporates the switching directly into the program syntax. Consider POE
code:
POE::Session-> create( inline_states => { state1 => sub { print "state1\n"; $_[ KERNEL]-> yield("state2"); }, state2 => sub { print "state2\n"; }, });
and correspodning IO::Lambda code:
lambda {
state1 {
print "state1\n";
state2 {
print "state2\n";
}}
}
Here, the programming style is (deliberately) not much different from the declarative
print "state1\n";
print "state2\n";
as much as the nature of asynchronous programming allows that.
To sum up, the intended use of IO::Lambda is for areas where simple
callback-based libraries require much additional work, and where state machines
are beneficial. Complex protocols like HTTP, parallel execution of several
tasks, strict control of task and protocol hierarchy - this is the domain where
IO::Lambda works best.
Given $filehandle is non-blocking, the following code creates a lambda
object (later, simply a lambda) that reads from the handle until EOF or an
error occured. Here, getline (see Stream IO below) constructs a lambda
that reads a single line from a filehandle.
use IO::Lambda qw(:all);
sub my_reader
{
my $filehandle = shift;
lambda {
context getline, $filehandle, \(my $buf = '');
tail {
my ( $string, $error) = @_;
if ( $error) {
warn "error: $error\n";
} else {
print $string;
return again;
}
}}
}
Assume we have two socket connections, and sockets are non-blocking - read from both of them in parallel. The following code creates a lambda that reads from two readers:
sub my_reader_all
{
my @filehandles = @_;
lambda {
context map { my_reader($_) } @filehandles;
tails { print "all is finished\n" };
}
}
my_reader_all( $socket1, $socket2)-> wait;
Given a socket, create a lambda that implements the HTTP protocol
use IO::Lambda qw(:all);
use IO::Socket;
use HTTP::Request;
sub talk
{
my $req = shift;
my $socket = IO::Socket::INET-> new( PeerAddr => 'www.perl.com', PeerPort => 80);
lambda {
context $socket;
write {
# connected
print $socket "GET ", $req-> uri, "\r\n\r\n";
my $buf = '';
read {
sysread $socket, $buf, 1024, length($buf) or return $buf;
again; # wait for reading and re-do the block
}
}
}
}
Connect and talk to the remote
$request = HTTP::Request-> new( GET => 'http://www.perl.com');
my $q = talk( $request );
print $q-> wait; # will print content of $buf
Connect two parallel connections: by explicitly waiting for each
$q = lambda {
context talk($request);
tail { print shift };
context talk($request2);
tail { print shift };
};
$q-> wait;
Connect two parallel connections: by waiting for all
$q = lambda {
context talk($request1), talk($request2);
tails { print for @_ };
};
$q-> wait;
Teach our simple http request to redirect by wrapping talk().
talk_redirect() will have exactly the same properties as talk() does
sub talk_redirect
{
my $req = shift;
lambda {
context talk( $req);
tail {
my $res = HTTP::Response-> parse( shift );
return $res unless $res-> code == 302;
$req-> uri( $res-> uri);
context talk( $req);
again;
}
}
}
use strict;
use IO::Lambda qw(:lambda);
use IO::Socket::INET;
sub get
{
my ( $socket, $url) = @_;
lambda {
context $socket;
write {
print $socket "GET $url HTTP/1.0\r\n\r\n";
my $buf = '';
read {
my $n = sysread( $socket, $buf, 1024, length($buf));
return "read error:$!" unless defined $n;
return $buf unless $n;
again;
}}}
}
sub get_parallel
{
my @hosts = @_;
lambda {
context map { get(
IO::Socket::INET-> new(
PeerAddr => $_,
PeerPort => 80
), '/index.html') } @hosts;
tails {
join("\n\n\n", @_ )
}
}
}
print get_parallel('www.perl.com', 'www.google.com')-> wait;
See tests and additional examples in directory eg/ for more information.
A lambda is an IO::Lambda object, that waits for IO and timeout events, and
for events generated when other lambdas are completed. On each such event a
callback is executed. The result of the execution is saved, and passed on to the
next callback, when the next event arrives.
Life cycle of a lambda goes through three modes: passive, waiting, and stopped.
A lambda that is just created, or was later reset with reset call, is in
passive state. When the lambda is started, the only callback associated with the
lambda will be executed:
$q = lambda { print "hello world!\n" };
# not printed anything yet
$q-> wait; # <- here will
Lambdas are usually not started explicitly; the function that waits for a
lambda, also starts it. wait, the synchronous waiter, and tail/tails,
the asynchronous ones, start passive lambdas when called. Lambda is finished
when there are no more events to listen to. The example lambda above will
finish right after print statement.
Lambda can listen to events by calling predicates, that internally subscribe
the lambda object to corresponding file handles, timers, and other lambdas.
There are only those three types of events that basically constitute everything
needed for building a state machine driven by external events, in particular,
by non-blocking I/O. Parameters passed to predicates with explicit context
call, not by perl subroutine call convention. In the example below,
lambda watches for file handle readability:
$q = lambda {
context \*SOCKET;
read { print "I'm readable!\n"; }
# here is nothing printed yet
};
# and here is nothing printed yet
Such lambda, when started, will switch to the waiting state, - will be waiting
for the socket. The lambda will finish only after the callback associated with
read predicate is called.
Of course, new events can be created inside all callbacks, on each state. This style resembles a dynamic programming of sorts, when the state machine is not hard-coded in advance, but is built as soon as code that gets there is executed.
The events can be created either by explicitly calling predicates, or by
restarting the last predicate with again call. For example, code
read { int(rand 2) ? print 1 : again }
will print indeterminable number of ones.
Each lambda callback (further on, merely lambda) executes in its own, private context. The context here means that all predicates register callbacks on an implicitly given lambda object, and keep the passed parameters on the context stack. The fact that context is preserved between states, helps building terser code with series of IO calls:
context \*SOCKET;
write {
read {
}}
is actually a shorter form for
context \*SOCKET;
write {
context \*SOCKET; # <-- context here is retained from one frame up
read {
}}
And as the context is kept, the current lambda object is also, in this
property. The code above is actually
my $self = this;
context \*SOCKET;
write {
this $self; # <-- object reference is retained here
context \*SOCKET;
read {
}}
this can be used if more than one lambda needs to be accessed. In which case,
this $object;
context @context;
is the same as
this $object, @context;
which means that explicitly setting this will always clear the context.
A lambda is initially called with arguments passed from outside. These
arguments can be stored using the call method; wait and tail also
issue call internally, thus replacing any previous data stored by call.
Inside the lambda these arguments are available as @_.
Whatever is returned by a predicate callback (including lambda predicate),
will be passed as @_ to the next callback, or to the outside, if the lambda
is finished. The result of a finished lambda is available by peek method,
that returns either all array of data available in the array context, or first
item in the array otherwise. wait returns the same data as peek does.
When more than one lambda watches for another lambda, the latter will get its last callback results passed to all the watchers. However, when a lambda creates more than one state that derive from the current state, a forking behaviour of sorts, the latest stored results will get overwritten by the first executed callback, so constructions like
read { 1 + shift };
write { 2 + shift };
...
wait(0)
will eventually return 3, but whether it will be 1+2 or 2+1, is not known.
wait is not the only function that synchronises input and output data.
wait_for_all method waits for all lambdas, including the caller, to finish.
It returns collected results of all the objects in a single list.
wait_for_any method waits for at least one lambda, from the list of passed
lambdas (again, including the caller), to finish. It returns list of finished
objects as soon as possible.
Timers and I/O timeouts can be given not only in the timeout values, as it usually is in event libraries, but also as deadlines in (fractional) seconds since epoch. This decision, strange at first sight, actually helps a lot when a total execution time is to be tracked. For example, the following code reads as many bytes as possible from a socket within 5 seconds:
lambda { my $buf = ''; context $socket, time + 5; read { if ( shift ) { return again if sysread $socket, $buf, 1024, length($buf); } else { print "oops! a timeout\n"; } $buf; } };
Rewriting the same code with read semantics that accepts time as a timeout
instead, would be not that elegant:
lambda { my $buf = ''; my $time_left = 5; my $now = time; context $socket, $time_left; read { if ( shift ) { if (sysread $socket, $buf, 1024, length($buf)) { $time_left -= (time - $now); $now = time; context $socket, $time_left; return again; } } else { print "oops! a timeout\n"; } $buf; } };
However, the exact opposite is true for sleep. The following two lines
both sleep 5 seconds:
lambda { context 5; sleep {} } lambda { context time + 5; sleep {} }
Internally, timers use Time::HiRes::time that gives the fractional number of
seconds. This however is not required for the caller, because when high-res
timers are not used, timeouts will simply be less precise, and will jitter
plus-minus half a second.
All predicates receive their parameters from the context stack, or simply the
context. The only parameter passed to them by using perl call, is the callback
itself. Predicates can also be called without a callback, in which case, they
will pass further data that otherwise would be passed as @_ to the
callback. Thus, a predicate can be called either as
read { .. code ... }
or
&read(); # no callback
Predicates can either be used after explicit exporting
use IO::Lambda qw(:lambda); lambda { ... }
or by using the package syntax,
use IO::Lambda; IO::Lambda::lambda { ... };
lambda()Creates a new IO::Lambda object.
io()Same as lambda.
Executes either when $filehandle becomes readable, or after $deadline.
Passes one argument, which is either TRUE if the handle is readable, or FALSE
if time is expired. If deadline is undef, then no timeout is registered,
that means that it will never be called with FALSE.
Exactly same as read, but executes when $filehandle becomes writable.
Executes either when $filehandle satisfies any of the condition $flags,
or after $deadline. $flags is a combination of three integer constants,
IO_READ, IO_WRITE, and IO_EXCEPTION, that are imported with
use IO::Lambda qw(:constants);
Passes one argument, which is either a combination of the same IO_XXX flags,
that report which conditions the handle satisfied, or 0 if time is expired. If
deadline is undef, no timeout is registered, i.e. will never return 0.
sleep($deadline)Executes after $deadline. $deadline cannot be undef.
Issues $lambda-> call(@parameters), then waits for the $lambda
to complete.
tails(@lambdas)Executes when all objects in @lambdas are finished, returns the collected,
unordered results of the objects.
tailo(@lambdas)Same as tails, but the results are ordered.
any_tail($deadline,@lambdas)Executes either when all objects in @lambdas are finished, or $deadline
expires. Returns lambdas that were successfully executed during the allotted
time.
Restarts the current state with the current context. All the predicates above,
excluding lambda, are restartable with again call (see start for
restarting a lambda). The code
context $obj1; tail { return if $null++; context $obj2; again; };
is thus equivalent to
context $obj1; tail { context $obj2; &tail(); };
again passes the current context to the predicate.
If @frame is provided, then it is treated as result of previous this_frame call.
It contains data sufficient to restarting another call, instead of the current.
See this_frame for details.
If called with no parameters, returns the current context, otherwise
replaces the current context with @ctx. It is thus not possible
(not that it is practical anyway) to clear the context with this call.
If really needed, use this(this) syntax.
If called with no parameters, returns the current lambda.
Otherwise, replaces both the current lambda and the current context.
Can be useful either when juggling with several lambdas, or as a
convenience over my variables, for example,
this lambda { ... };
this-> wait;
instead of
my $q = lambda { ... };
$q-> wait;
this_frame(@frame)If called without parameters, returns the current callback frame, that
can be later used in again. Otherwise, replaces the internal frame
variables, that doesn't affect anything immediately, but will be used by again
that is called without parameters.
This property is only used when the predicate inside which this_frame was
fetched, is restartable. Since it is not a requirement for a user-defined
predicate to be restartable, this property is not universally useful.
Example:
context lambda { 1 };
tail {
return if 3 == shift;
my @frame = this_frame;
context lambda { 2 };
tail {
context lambda { 3 };
again( @frame);
}
}
The outermost tail callback will be called twice: first time in the normal course of events,
and second time as a result of the again call. this_frame and again thus provide
a kind of restartable continuations.
Helper function for creating predicates, either from lambdas or from lambda constructors.
Example: convert existing getline constructor into a predicate:
sub gl(&) { getline-> call(context)-> predicate( shift, \&gl, 'gl') } ... context $fh, $buf, $deadline; gl { ... }
The whole point of this module is to help building complex protocols in a
clear, consequent programming style. Consider how perl's low-level sysread
and syswrite relate to its higher-level readline, where the latter not
only does the buffering, but also recognizes $/ as input record separator.
The section above described lower-level lambda I/O predicates, that are only
useful for sysread and syswrite; this section tells about higher-level
lambdas that relate to these low-level ones, as the aforementioned readline
relates to sysread.
All functions in this section return the lambda, that does the actual work.
Not unlike as a class constructor returns a newly created class instance, these
functions return newly created lambdas. Such functions will be further referred
as lambda constructors, or simply constructors. Therefore, constructors are
documented here as having two inputs and one output, as for example a function
sysreader is a function that takes 0 parameters, always returns a new
lambda, and this lambda, in turn, takes four parameters and returns two. This
constructor will be described as
# sysreader() :: ($fh,$buf,$length,$deadline) -> ($result,$error)
Since all stream I/O lambdas return same set of scalars, the return type
will be further on referred as ioresult:
# ioresult :: ($result, $error)
# sysreader() :: ($fh,$buf,$length,$deadline) -> ioresult
ioresult's first scalar is defined on success, and is not otherwise. In the
latter case, the second scalar contains the error, usually either $! or
'timeout' (if $deadline was set).
Before describing the actual functions, consider the code that uses them. Let's take a lambda that needs to implement a very simple HTTP/0.9 request:
lambda { my $handle = shift; my $buf = ''; context getline, $handle, $buf; tail { my $req = shift; die "bad request" unless $req =~ m[GET (.*)$]i; do_request($handle, $1); }}
getline will read from $handle to $buf, and will wake up when new line
is there. However, what if we need, for example, HTTPS instead of HTTP, where
reading from socket may involve some writing, and of course some, waiting?
Then the first default parameter to getline has to be replaced. By default,
context getline, $handle, $buf;
is the same as
my $reader = sysreader; context getline($reader), $handle, $buf;
where sysreader creates a lambda $reader, that given $handle, waits
when it becomes readable, and reads from it. getline, in turn, repeatedly
calls $reader, until the whole line is read.
Thus, we call
context getline(https_reader), $handle, $buf;
instead, that should conform to sysreader signature:
sub https_reader { lambda { my ( $fh, $buf, $length, $deadline) = @_; # read from SSL socket return $error ? (undef, $error) : $data; } }
I don't show the actual implementation of a HTTPS read (if you're curious, look
at the IO::Lambda::HTTPS manpage ), but the idea is that inside that reader, it is
perfectly fine to do any number of read and write operations, and wait for
their completion, as long as the lambda will sooner or later return the data.
getline (or, rather, readbuf that getline is based on) won't care
about internal states of the reader.
Note: check out t/06_stream.t that emulates reading and writing in this fashion.
sysreader() :: ($fh, $buf, $length, $deadline) -> ioresultCreates a lambda that accepts all the parameters used by sysread (except
$offset though), plus $deadline. The lambda tries to read $length
bytes from $fh into $buf, when $fh becomes available for reading. If
$deadline expires, fails with 'timeout' error. On successful read,
returns number of bytes read, or $! otherwise.
syswriter() :: ($fh, $buf, $length, $offset, $deadline) -> ioresultCreates a lambda that accepts all the parameters used by syswrite plus
$deadline. The lambda tries to write $length bytes to $fh from $buf
from $offset, when $fh becomes available for writing. If $deadline
expires, fails with 'timeout' error. On successful write, returns number of
bytes written, or $! otherwise.
Creates a lambda that is able to perform buffered reads from $fh, either
using custom lambda reader, or using one newly generated by sysreader.
The lambda when called, will read continually from $fh into $buf, and
will either fail on timeout, I/O error, or end of file, or succeed if $cond
condition matches.
The condition $cond is a "smart match" of sorts, and can be one of:
The lambda will succeed when exactly $cond bytes are read from $fh.
The lambda will succeed when $cond matches the content of $buf.
Note that readbuf saves and restores value of pos($$buf), so use of
\G is encouraged here.
The lambda will succeed if coderef called with $buf returns true value.
The lambda will succeed on end of file. Note that for all other conditions end
of file is reported as an error, with literal "eof" string.
writebuf($writer) :: ($fh, $buf, $length, $offset, $deadline) -> ioresultCreates a lambda that is able to perform buffered writes to $fh, either
using custom lambda writer, or using one newly generated by syswriter.
That lambda, in turn, will write continually $buf (from $offset,
$length bytes) and will either fail on timeout or I/O error, or succeed when
$length bytes are written successfully.
getline($reader) :: ($fh, $buf, $deadline) -> ioresultSame as readbuf, but succeeds when a string of bytes ended by a newline
is read.
This section lists methods of IO::Lambda class. Note that by design all
lambda-style functionality is also available for object-style programming.
Together with the fact that lambda syntax is not exported by default, it thus
leaves a place for possible implementations of user-defined syntax, either
with or without lambdas, on top of the object API, without accessing the
internals.
The object API is mostly targeted to developers that need to connect third-party asynchronous events with the lambda interface.
Creates new IO::Lambda object in the passive state. $start
will be called once, after the lambda gets active.
Registers an IO event listener that will call $callback either after
$handle will satisfy condition of $flags ( a combination of IO_READ,
IO_WRITE, and IO_EXCEPTION bits), or after $deadline time is passed. If
$deadline is undef, will watch for the file handle indefinitely.
The callback will be called with first parameter as integer set of IO_XXX flags, or 0 if timed out. Other parameters, as with the other callbacks, will be passed the result of the last called callback. The result of the callback will be stored and passed on to the next callback.
Registers a timer listener that will call $callback after
$deadline time.
Registers a listener that will call $callback after $lambda,
a IO::Lambda object is finished. If $lambda is in passive state,
it will be started first.
Reports whether lambda is stopped or not.
Reports whether lambda has any registered callbacks left or not.
Reports if lambda wasn't run yet, -- either after new
or reset.
Reports if lambda was run.
Cancels all watchers and switches the lambda to the passive state. If there are any lambdas that watch for this object, these will be called first.
At any given time, returns stored data that are either passed
in by call if the lambda is in the passive state, or stored result
of execution of the latest callback.
Starts a passive lambda. Can be used for effective restart of the whole lambda; the only requirement is that the lambda should have no pending events.
Stores @args internally, to be passed on to the first callback. Only
works in passive state, croaks otherwise. If called multiple times,
arguments from the previous calls are overwritten.
Cancels all watchers and resets lambda to the stopped state. If there are any
lambdas that watch for this object, these will be notified first. @args will
be stored and available for later calls by peek.
Cancels all watchers and resets lambda to the stopped state. Does the same to
all lambdas the caller lambda watches after, recursively. Useful where
explicit, long-lived lambdas shouldn't be subject to global destruction, which
kills objects in random order; destroy kills them in some order, at least.
Waits for the caller lambda to finish, returns the result of peek.
If the object was in passive state, calls call(@args), otherwise
@args are not used.
Waits for caller lambda and @lambdas to finish. Returns
collection of peek results for all objects. The results
are unordered.
Waits for at least one lambda from list of caller lambda and @lambdas to
finish. Returns list of finished objects.
Runs one round of dispatching events. Returns 1 if there are more events
in internal queues, 0 otherwise. If $NONBLOCKING is set, exits as soon
as possible, otherwise waits for events; this feature can be used for
organizing event loops without wait/run calls.
Enters the event loop and doesn't exit until there are no registered events. Can be also called as package method.
Creates an event record that contains the lambda and @args, and returns it.
The lambda won't finish until this event is returned with resolve.
bind can be called several times on a single lambda; each event requires
individual resolve.
Removes $event from the internal waiting list. If lambda has no more
events to wait, notifies eventual lambdas that wait to the objects, and
then stops.
Note that resolve doesn't provide any means to call associated
callbacks, which is intentional.
Installs a $coderef as an overriding hook for a predicate callback, where
predicate is tail, read, write, etc. Whenever a predicate callback
is being called, the $coderef hook will be called instead, that should be able to
analyze the call, and allow or deny it the further processing.
$state, if omitted, is equivalent to '*', that means that checks on
lambda state are omitted too. Setting $state to undef is allowed though,
and will match when the lambda state is also undefined (which it is by
default).
There can exist more than one intercept handlers, stacked on top of each
other. If $coderef is undef, the last registered hook is removed.
Example:
my $q = lambda { ... tail { ... }};
$q-> intercept( tail => sub {
if ( stars are aligned right) {
# pass
return this-> super(@_);
} else {
return 'not right';
}
});
See also state, super, and override.
Installs a $coderef as an overriding hook for a predicate - tail, read,
write, etc, possibly with a named state. Whenever a lambda calls one of
these predicates, the $coderef hook will be called instead, that should be
able to analyze the call, and allow or deny it the further processing.
$state, if omitted, is equivalent to '*', that means that checks on lambda
state are omitted too. Setting $state to undef is allowed though, and will
match when the lambda state is also undefined (which it is by default).
There can exist more than one override handlers, stacked on top of each
other. If $coderef is undef, the last registered hook is removed.
Example:
my $q = lambda { ... tail { ... }};
$q-> override( tail => sub {
if ( stars are aligned right) {
# pass
this-> super;
} else {
# deny and rewrite result
return tail { 'not right' }
}
});
See also state, super, and intercept.
Analogous to Perl's SUPER, but on the predicate level, this method is
designed to be called from overridden predicates to call the original predicate
or callback.
There is a slight difference in the call syntax, depending on whether it is
being called from inside an override or intercept callback. The
intercept'ed callback will call the previous callback right away, and may
call it with parameters directly. The override callback will only call the
predicate registration routine itself, not the callback, and therefore is
called without parameters. See intercept and override for examples of
use.
A helper function for explicit naming of predicate calls. The function stores
the $state string on the current lambda; this string can be used in calls
to intercept and override to identify a particular predicate or a callback.
The recommended use of the method is when a lambda contains more than one predicate of a certain type; for example the code
tail { tail { ... }}
is therefore better to be written as
state A => tail { state B => tail { ... }}
Helper modules:
the IO::Lambda::Signal manpage - POSIX signals.
the IO::Lambda::Socket manpage - lambda versions of connect, accept etc.
the IO::Lambda::HTTP manpage - implementation of HTTP and HTTPS protocols. HTTPS requires the IO::Socket::SSL manpage, NTLM/Negotiate authentication requires the Authem::NTLM manpage modules (not marked as dependencies).
the IO::Lambda::DNS manpage - asynchronous domain name resolver.
the IO::Lambda::SNMP manpage - SNMP requests lambda style. Requires the SNMP manpage.
A single-process TCP client and server; server echoes back everything is sent by the client. 500 connections sequentially created, instructed to send a single line to the server, and destroyed.
2.4GHz x86-64 linux 1.2GHz win32
Lambda using select 0.694 sec 6.364 sec
Lambda using AnyEvent 0.684 sec 7.031 sec
Raw sockets using select 0.145 sec 4.141 sec
POE using select 5.349 sec 14.887 sec
See benchmarking code in eg/bench.
Copyright (c) 2008 capmon ApS. All rights reserved.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Dmitry Karasik, <dmitry@karasik.eu.org>.