small compared to execution of the state machine, which is coded pretty
optimally within L<AnyEvent::Impl::POE> (and while everybody agrees that
using multiple sessions is not a good approach, especially regarding
memory usage, even the author of POE could not come up with a faster
design).
=head3 Summary
=over 4
=item * Using EV through AnyEvent is faster than any other event loop
(even when used without AnyEvent), but most event loops have acceptable
performance with or without AnyEvent.
=item * The overhead AnyEvent adds is usually much smaller than the overhead of
the actual event loop, only with extremely fast event loops such as EV
adds AnyEvent significant overhead.
=item * You should avoid POE like the plague if you want performance or
reasonable memory usage.
=back
=head2 BENCHMARKING THE LARGE SERVER CASE
This benchmark actually benchmarks the event loop itself. It works by
creating a number of "servers": each server consists of a socket pair, a
timeout watcher that gets reset on activity (but never fires), and an I/O
watcher waiting for input on one side of the socket. Each time the socket
watcher reads a byte it will write that byte to a random other "server".
The effect is that there will be a lot of I/O watchers, only part of which
are active at any one point (so there is a constant number of active
fds for each loop iteration, but which fds these are is random). The
timeout is reset each time something is read because that reflects how
most timeouts work (and puts extra pressure on the event loops).
In this benchmark, we use 10000 socket pairs (20000 sockets), of which 100
(1%) are active. This mirrors the activity of large servers with many
connections, most of which are idle at any one point in time.
Source code for this benchmark is found as F<eg/bench2> in the AnyEvent
distribution.
=head3 Explanation of the columns
I<sockets> is the number of sockets, and twice the number of "servers" (as
each server has a read and write socket end).
I<create> is the time it takes to create a socket pair (which is
nontrivial) and two watchers: an I/O watcher and a timeout watcher.
I<request>, the most important value, is the time it takes to handle a
single "request", that is, reading the token from the pipe and forwarding
it to another server. This includes deleting the old timeout and creating
a new one that moves the timeout into the future.
=head3 Results
name sockets create request
EV 20000 69.01 11.16
Perl 20000 73.32 35.87
Event 20000 212.62 257.32
Glib 20000 651.16 1896.30
POE 20000 349.67 12317.24 uses POE::Loop::Event
=head3 Discussion
This benchmark I<does> measure scalability and overall performance of the
particular event loop.
EV is again fastest. Since it is using epoll on my system, the setup time
is relatively high, though.
Perl surprisingly comes second. It is much faster than the C-based event
loops Event and Glib.
Event suffers from high setup time as well (look at its code and you will
understand why). Callback invocation also has a high overhead compared to
the C<< $_->() for .. >>-style loop that the Perl event loop uses. Event
uses select or poll in basically all documented configurations.
Glib is hit hard by its quadratic behaviour w.r.t. many watchers. It
clearly fails to perform with many filehandles or in busy servers.
POE is still completely out of the picture, taking over 1000 times as long
as EV, and over 100 times as long as the Perl implementation, even though
it uses a C-based event loop in this case.
=head3 Summary
=over 4
=item * The pure perl implementation performs extremely well.
=item * Avoid Glib or POE in large projects where performance matters.
=back
=head2 BENCHMARKING SMALL SERVERS
=16= |