NAME
IO::Async
- Asynchronous event-driven programming
SYNOPSIS
use IO::Async::Stream;
use IO::Async::Loop;
my $loop = IO::Async::Loop->new;
$loop->connect(
host => "some.other.host",
service => 12345,
socktype => 'stream',
on_stream => sub {
my ( $stream ) = @_;
$stream->configure(
on_read => sub {
my ( $self, $buffref, $eof ) = @_;
while( $$buffref =~ s/^(.*\n)// ) {
print "Received a line $1";
}
return 0;
}
);
$stream->write( "An initial line here\n" );
$loop->add( $stream );
},
on_resolve_error => sub { die "Cannot resolve - $_[-1]\n"; },
on_connect_error => sub { die "Cannot connect - $_[0] failed $_[-1]\n"; },
);
$loop->loop_forever;
DESCRIPTION
This collection of modules allows programs to be written that perform asynchronous filehandle IO operations. A typical program using them would consist of a single subclass of IO::Async::Loop to act as a container of other objects, which perform the actual IO work required by the program. As well as IO handles, the loop also supports timers and signal handlers, and includes more higher-level functionality built on top of these basic parts.
Because there are a lot of classes in this collection, the following overview gives a brief description of each.
Notifiers
The base class of all the event handling subclasses is IO::Async::Notifier. It does not perform any IO operations itself, but instead acts as a base class to build the specific IO functionality upon. It can also coordinate a collection of other Notifiers contained within it, forming a tree structure.
The following sections describe particular types of Notifier.
File Handle IO
An IO::Async::Handle object is a Notifier that represents a single IO handle being managed. While in most cases it will represent a single filehandle, such as a socket (for example, an IO::Socket::INET connection), it is possible to have separate reading and writing handles (most likely for a program's STDIN
and STDOUT
streams, or a pair of pipes connected to a child process).
The IO::Async::Stream class is a subclass of IO::Async::Handle which maintains internal incoming and outgoing data buffers. In this way, it implements bidirectional buffering of a byte stream, such as a TCP socket. The class automatically handles reading of incoming data into the incoming buffer, and writing of the outgoing buffer. Methods or callbacks are used to inform when new incoming data is available, or when the outgoing buffer is empty.
While stream-based sockets can be handled using using IO::Async::Stream
, datagram or raw sockets do not provide a bytestream. For these, the IO::Async::Socket class is another subclass of IO::Async::Handle which maintains an outgoing packet queue, and informs of packet receipt using a callback or method.
The IO::Async::Listener class is another subclass of IO::Async::Handle which facilitates the use of listen(2)
-mode sockets. When a new connection is available on the socket it will accept(2)
it and pass the new client socket to its callback function.
Timers
An IO::Async::Timer::Absolute object represents a timer that expires at a given absolute time in the future.
An IO::Async::Timer::Countdown object represents a count time timer, which will invoke a callback after a given delay. It can be stopped and restarted.
An IO::Async::Timer::Periodic object invokes a callback at regular intervals from its initial start time. It is reliable and will not drift due to the time taken to run the callback.
The IO::Async::Loop also supports methods for managing timed events on a lower level. Events may be absolute, or relative in time to the time they are installed.
Signals
An IO::Async::Signal object represents a POSIX signal, which will invoke a callback when the given signal is received by the process. Multiple objects watching the same signal can be used; they will all invoke in no particular order.
Processes Management
An IO::Async::PID object invokes its event when a given child process exits. An IO::Async::Process object can start a new child process running either a given block of code, or executing a given command, set up pipes on its filehandles, write to or read from these pipes, and invoke its event when the child process exits.
Loops
The IO::Async::Loop object class represents an abstract collection of IO::Async::Notifier objects, and manages the actual filehandle IO watchers, timers, signal handlers, and other functionality. It performs all of the abstract collection management tasks, and leaves the actual OS interactions to a particular subclass for the purpose.
IO::Async::Loop::Poll uses an IO::Poll object for this test.
IO::Async::Loop::Select uses the select(2)
syscall.
Other subclasses of loop may appear on CPAN under their own dists; such as IO::Async::Loop::Glib which acts as a proxy for the Glib::MainLoop
of a Glib-based program, or IO::Async::Loop::Ppoll which uses the IO::Ppoll object to handle signals safely on Linux.
As well as these general-purpose classes, the IO::Async::Loop constructor also supports looking for OS-specific subclasses, in case a more efficient implementation exists for the specific OS it runs on.
Child Processes
The IO::Async::Loop object provides a number of methods to facilitate the running of child processes. spawn_child
is primarily a wrapper around the typical fork(2)
/exec(2)
style of starting child processes, and run_child
provide a method similar to perl's readpipe
(which is used to implement backticks ``
).
Asynchronous Co-routines and Functions
The IO::Async
framework generally provides mechanisms for multiplexing IO tasks between different handles, so there aren't many occasions when it is necessary to run code in another thread or process. Two cases where this does become useful are when:
A large amount of computationally-intensive work needs to be performed.
An OS or library-level function needs to be called, that will block, and no asynchronous version is supplied.
For these cases, an instance of IO::Async::Function can be used around a code block, to execute it in a worker child process or set of processes. The code in the sub-process runs isolated from the main program, communicating only by function call arguments and return values. This can be used to solve problems involving state-less library functions.
An IO::Async::Routine object wraps a code block running in a separate process to form a kind of co-routine. Communication with it happens via IO::Async::Channel objects. It can be used to solve any sort of problem involving keeping a possibly-stateful co-routine running alongside the rest of an asynchronous program.
Networking
The IO::Async::Loop provides several methods for performing network-based tasks. Primarily, the connect
and listen
methods allow the creation of client or server network sockets. Additionally, the resolve
method allows the use of the system's name resolvers in an asynchronous way, to resolve names into addresses, or vice versa. These methods are fully IPv6-capable if the underlying operating system is.
Protocols
The IO::Async::Protocol class provides storage for a IO::Async::Handle object, to act as a transport for some protocol. It allows a level of independence from the actual transport being for that protocol, allowing it to be easily reused. The IO::Async::Protocol::Stream subclass provides further support for protocols based on stream connections, such as TCP sockets.
TODO
This collection of modules is still very much in development. As a result, some of the potentially-useful parts or features currently missing are:
An IO::Async::Loop subclass to perform integration with Event. Consider further ideas on Solaris' ports, BSD's Kevents and anything that might be useful on Win32.
A consideration on how to provide per-OS versions of the utility classes. For example, Win32 would probably need an extensively-different
ChildManager
, or OSes may have specific ways to perform asynchronous name resolution operations better than the genericIO::Async::Function
approach. This should be easier to implement now that the IO::Async::Loop magic constructor looks for OS-specific subclasses first.Consider some form of persistent object wrapper in the form of an
IO::Async::Object
, based onIO::Async::Routine
.Build some sort of future-like system, possibly called
IO::Async::Task
to represent one-shot events like name resolver lookups, socket connects, etc.. Replace uses ofAsync::MergePoint
with it, removing a dependency. UseCPS::Future
.IO::Async::Protocol::Datagram
Support for watching filesystem entries for change. Extract logic from
IO::Async::FileStream
. Define Loop watch/unwatch method pair.
SUPPORT
Bugs may be reported via RT at
https://rt.cpan.org/Public/Dist/Display.html?Name=IO-Async
Support by IRC may also be found on irc.perl.org in the #io-async channel.
AUTHOR
Paul Evans <leonerd@leonerd.org.uk>