--- AnyEvent/lib/AnyEvent.pm 2008/04/25 07:14:33 1.68 +++ AnyEvent/lib/AnyEvent.pm 2008/04/25 13:39:08 1.83 @@ -82,9 +82,9 @@ During the first call of any watcher-creation method, the module tries to detect the currently loaded event loop by probing whether one of the following modules is already loaded: L, L, L, -L, L, L, L, L, L, +L, L, L, L, L, L, L. The first one found is used. If none are found, the module tries -to load these modules (excluding Event::Lib, Qt and POE as the pure perl +to load these modules (excluding Tk, Event::Lib, Qt and POE as the pure perl adaptor should always succeed) in the order given. The first one that can be successfully loaded will be used. If, after this, still none could be found, AnyEvent will fall back to a pure-perl event loop, which is not @@ -138,7 +138,7 @@ my variables are only visible after the statement in which they are declared. -=head2 IO WATCHERS +=head2 I/O WATCHERS You can create an I/O watcher by calling the C<< AnyEvent->io >> method with the following mandatory key-value pairs as arguments: @@ -149,9 +149,7 @@ respectively. C is the callback to invoke each time the file handle becomes ready. -As long as the I/O watcher exists it will keep the file descriptor or a -copy of it alive/open. - +The I/O watcher might use the underlying file descriptor or a copy of it. It is not allowed to close a file handle as long as any watcher is active on the underlying file descriptor. @@ -255,16 +253,38 @@ signal handler for C. The callback will be called with the pid and exit status (as returned by waitpid). -Example: wait for pid 1333 +There is a slight catch to child watchers, however: you usually start them +I the child process was created, and this means the process could +have exited already (and no SIGCHLD will be sent anymore). + +Not all event models handle this correctly (POE doesn't), but even for +event models that I handle this correctly, they usually need to be +loaded before the process exits (i.e. before you fork in the first place). + +This means you cannot create a child watcher as the very first thing in an +AnyEvent program, you I to create at least one watcher before you +C the child (alternatively, you can call C). + +Example: fork a process and wait for it + + my $done = AnyEvent->condvar; + + AnyEvent::detect; # force event module to be initialised + + my $pid = fork or exit 5; my $w = AnyEvent->child ( - pid => 1333, + pid => $pid, cb => sub { my ($pid, $status) = @_; warn "pid $pid exited with status $status"; + $done->broadcast; }, ); + # do something else, then wait for process exit + $done->wait; + =head2 CONDITION VARIABLES Condition variables can be created by calling the C<< AnyEvent->condvar >> @@ -361,8 +381,8 @@ AnyEvent::Impl::EV based on EV (an interface to libev, best choice). AnyEvent::Impl::Event based on Event, second best choice. AnyEvent::Impl::Glib based on Glib, third-best choice. - AnyEvent::Impl::Tk based on Tk, very bad choice. AnyEvent::Impl::Perl pure-perl implementation, inefficient but portable. + AnyEvent::Impl::Tk based on Tk, very bad choice. AnyEvent::Impl::Qt based on Qt, cannot be autoprobed (see its docs). AnyEvent::Impl::EventLib based on Event::Lib, leaks memory and worse. AnyEvent::Impl::POE based on POE, not generic enough for full support. @@ -708,7 +728,7 @@ =head1 EXAMPLE PROGRAM -The following program uses an IO watcher to read data from STDIN, a timer +The following program uses an I/O watcher to read data from STDIN, a timer to display a message once per second, and a condition variable to quit the program when the user enters quit: @@ -866,13 +886,19 @@ =head1 BENCHMARK To give you an idea of the performance and overheads that AnyEvent adds -over the event loops directly, here is a benchmark of various supported +over the event loops themselves (and to give you an impression of the +speed of various event loops), here is a benchmark of various supported event models natively and with anyevent. The benchmark creates a lot of -timers (with a zero timeout) and io watchers (watching STDOUT, a pty, to +timers (with a zero timeout) and I/O watchers (watching STDOUT, a pty, to become writable, which it is), lets them fire exactly once and destroys them again. -=head2 Explanation of the fields +Rewriting the benchmark to use many different sockets instead of using +the same filehandle for all I/O watchers results in a much longer runtime +(socket creation is expensive), but qualitatively the same figures, so it +was not used. + +=head2 Explanation of the columns I is the number of event watchers created/destroyed. Since different event models feature vastly different performances, each event @@ -892,68 +918,89 @@ I is the time, in microseconds, used to invoke a simple callback. The callback simply counts down a Perl variable and after it was -invoked "watcher" times, it would C<< ->broadcast >> a condvar once. +invoked "watcher" times, it would C<< ->broadcast >> a condvar once to +signal the end of this phase. -I is the time, in microseconds, that it takes destroy a single +I is the time, in microseconds, that it takes to destroy a single watcher. =head2 Results - name watcher bytes create invoke destroy comment - EV/EV 400000 244 0.56 0.46 0.31 EV native interface - EV/Any 100000 610 3.52 0.91 0.75 - CoroEV/Any 100000 610 3.49 0.92 0.75 coroutines + Coro::Signal - Perl/Any 10000 654 4.64 1.22 0.77 pure perl implementation - Event/Event 10000 523 28.05 21.38 5.22 Event native interface - Event/Any 10000 943 34.43 20.48 1.39 - Glib/Any 16000 1357 96.99 12.55 55.51 quadratic behaviour - Tk/Any 2000 1855 27.01 66.61 14.03 SEGV with >> 2000 watchers - POE/Select 2000 6343 94.69 807.65 562.69 POE::Loop::Select - POE/Event 2000 6644 108.15 768.19 14.33 POE::Loop::Event + name watchers bytes create invoke destroy comment + EV/EV 400000 244 0.56 0.46 0.31 EV native interface + EV/Any 100000 244 2.50 0.46 0.29 EV + AnyEvent watchers + CoroEV/Any 100000 244 2.49 0.44 0.29 coroutines + Coro::Signal + Perl/Any 100000 513 4.92 0.87 1.12 pure perl implementation + Event/Event 16000 516 31.88 31.30 0.85 Event native interface + Event/Any 16000 936 39.17 33.63 1.43 Event + AnyEvent watchers + Glib/Any 16000 1357 98.22 12.41 54.00 quadratic behaviour + Tk/Any 2000 1860 26.97 67.98 14.00 SEGV with >> 2000 watchers + POE/Event 2000 6644 108.64 736.02 14.73 via POE::Loop::Event + POE/Select 2000 6343 94.13 809.12 565.96 via POE::Loop::Select =head2 Discussion The benchmark does I measure scalability of the event loop very well. For example, a select-based event loop (such as the pure perl one) can never compete with an event loop that uses epoll when the number of -file descriptors grows high. In this benchmark, only a single filehandle -is used (although some of the AnyEvent adaptors dup() its file descriptor -to worka round bugs). +file descriptors grows high. In this benchmark, all events become ready at +the same time, so select/poll-based implementations get an unnatural speed +boost. C is the sole leader regarding speed and memory use, which are both -maximal/minimal, respectively. Even when going through AnyEvent, there is -only one event loop that uses less memory (the C module natively), and -no faster event model, not event C natively. +maximal/minimal, respectively. Even when going through AnyEvent, there are +only two event loops that use slightly less memory (the C module +natively and the pure perl backend), and no faster event models, not even +C natively. The pure perl implementation is hit in a few sweet spots (both the zero timeout and the use of a single fd hit optimisations in the perl -interpreter and the backend itself). Nevertheless tis shows that it -adds very little overhead in itself. Like any select-based backend its -performance becomes really bad with lots of file descriptors, of course, -but this was not subjetc of this benchmark. +interpreter and the backend itself, and all watchers become ready at the +same time). Nevertheless this shows that it adds very little overhead in +itself. Like any select-based backend its performance becomes really bad +with lots of file descriptors (and few of them active), of course, but +this was not subject of this benchmark. The C module has a relatively high setup and callback invocation cost, but overall scores on the third place. -C's memory usage is quite a bit bit higher, features a faster -callback invocation and overall lands in the same class as C. +C's memory usage is quite a bit bit higher, but it features a +faster callback invocation and overall ends up in the same class as +C. However, Glib scales extremely badly, doubling the number of +watchers increases the processing time by more than a factor of four, +making it completely unusable when using larger numbers of watchers +(note that only a single file descriptor was used in the benchmark, so +inefficiencies of C do not account for this). -The C adaptor works relatively well, the fact that it crashes with +The C adaptor works relatively well. The fact that it crashes with more than 2000 watchers is a big setback, however, as correctness takes precedence over speed. Nevertheless, its performance is surprising, as the file descriptor is dup()ed for each watcher. This shows that the dup() employed by some adaptors is not a big performance issue (it does incur a -hidden memory cost inside the kernel, though). +hidden memory cost inside the kernel, though, that is not reflected in the +figures above). + +C, regardless of underlying event loop (wether using its pure perl +select-based backend or the Event module) shows abysmal performance and +memory usage: Watchers use almost 30 times as much memory as EV watchers, +and 10 times as much memory as both Event or EV via AnyEvent. Watcher +invocation is almost 900 times slower than with AnyEvent's pure perl +implementation. The design of the POE adaptor class in AnyEvent can not +really account for this, as session creation overhead is small compared +to execution of the state machine, which is coded pretty optimally within +L. POE simply seems to be abysmally slow. + +=head2 Summary + +Using EV through AnyEvent is faster than any other event loop, but most +event loops have acceptable performance with or without AnyEvent. + +The overhead AnyEvent adds is usually much smaller than the overhead of +the actual event loop, only with extremely fast event loops such as the EV +adds AnyEvent significant overhead. -C, regardless of backend (wether using its pure perl select-based -backend or the Event backend) shows abysmal performance and memory -usage: Watchers use almost 30 times as much memory as EV watchers, and 10 -times as much memory as both Event or EV via AnyEvent. Watcher invocation -is almost 700 times slower as with AnyEvent's pure perl implementation. - -Summary: using EV through AnyEvent is faster than any other event -loop. The overhead AnyEvent adds can be very small, and you should avoid -POE like the plague if you want performance or reasonable memory usage. +And you should simply avoid POE like the plague if you want performance or +reasonable memory usage. =head1 FORK