AnyEvent

 view release on metacpan or  search on metacpan

lib/AnyEvent/Impl/POE.pm  view on Meta::CPAN

reason.

=item One POE session per Event

AnyEvent has to create one POE::Session per event watcher, which is
immensely slow and makes watchers very large. The reason for this is
lacking lifetime management (mostly undocumented, too). Without one
session/watcher it is not possible to easily keep the kernel from running
endlessly.

This is not just a problem with the way AnyEvent has to interact with
POE, but is a principal issue with POEs lifetime management (namely
that stopping the kernel stops sessions, but AnyEvent has no control
over who and when the kernel starts or stops w.r.t. AnyEvent watcher
creation/destruction).

From benchmark data it is not clear that session creation is that costly,
though - the real inefficiencies with POE seem to come from other sources,
such as event handling.

=item One watcher per fd/event combo

POE, of course, suffers from the same bug as Tk and some other badly
designed event models in that it doesn't support multiple watchers per
fd/poll combo. The workaround is the same as with Tk: AnyEvent::Impl::POE
creates a separate file descriptor to hand to POE, which isn't fast and
certainly not nice to your resources.

Of course, without the workaround, POE also prints ugly messages again
that say the program *might* be buggy.

While this is not good to performance, at least regarding speed, with a
modern Linux kernel, the overhead is actually quite small.

=item Timing deficiencies

POE manages to not have a function that returns the current time. This is
extremely problematic, as POE can use different time functions, which can
differ by more than a second - and user code is left guessing which one is
used.

In addition, most timer functions in POE want an absolute timestamp, which
is hard to create if all you have is a relative time and no function to
return the "current time".

And of course POE doesn't handle time jumps at all (not even when using
an event loop that happens to do that, such as L<EV>, as it does its own
unoptimised timer management).

AnyEvent works around the unavailability of the current time using
relative timers exclusively, in the hope that POE gets it right at least
internally.

=item Lack of defined event ordering

POE cannot guarantee the order of callback invocation for timers, and
usually gets it wrong. That is, if you have two timers, one timing out
after another (all else being equal), the callbacks might be called in
reverse order.

How one manages to even implement stuff that way escapes me.

=item Child watchers

POE offers child watchers - which is a laudable thing, as few event loops
do. Unfortunately, they cannot even implement AnyEvent's simple child
watchers: they are not generic enough (the POE implementation isn't even
generic enough to let properly designed back-end use their native child
watcher instead - it insist on doing it itself the broken way).

Unfortunately, POE's child handling is inherently racy: if the child exits
before the handler is created (because e.g. it crashes or simply is quick
about it), then current versions of POE (1.352) will I<never> invoke the
child watcher, and there is nothing that can be done about it. Older
versions of POE only delayed in this case. The reason is that POE first
checks if the child has already exited, and I<then> installs the signal
handler - aa classical race.

Your only hope is for the fork'ed process to not exit too quickly, in
which case everything happens to work.

Of course, whenever POE reaps an unrelated child it will also output a
message for it that you cannot suppress (which shouldn't be too surprising
at this point). Very professional.

As a workaround, AnyEvent::Impl::POE will take advantage of undocumented
behaviour in POE::Kernel to catch the status of all child processes, but
it cannot guarantee delivery.

How one manages to have such a glaring bug in an event loop after ten
years of development escapes me.

(There are more annoying bugs, for example, POE runs C<waitpid>
unconditionally at finaliser time, so your program will hang until all
child processes have exited.)

=item Documentation quality

At the time of this writing, POE was in its tenth year. Still, its
documentation is extremely lacking, making it impossible to implement
stuff as trivial as AnyEvent watchers without having to resort to
undocumented behaviour or features.

For example, the POE::Kernel manpage has nine occurrences of the word TODO
with an explanation of whats missing. In general, the POE man pages are
littered with comments like "section not yet written".

Some other gems:

   This allows many object methods to also be package methods.

This is nice, but since it doesn't document I<which> methods these are,
this is utterly useless information.

   Terminal signals will kill sessions if they are not handled by a
   "sig_handled"() call. The OS signals that usually kill or dump a
   process are considered terminal in POE, but they never trigger a
   coredump. These are: HUP, INT, QUIT and TERM.

Although AnyEvent calls C<sig_handled>, removing it has no apparent
effects on POE handling SIGINT.

   refcount_increment SESSION_ID, COUNTER_NAME

Nowhere is explained which COUNTER_NAMEs are valid and which aren't - not
all scalars (or even strings) are valid counter names. Take your guess,
failure is of course completely silent. I found this out the hard way, as
the first name I came up with was silently ignored.

   get_next_event_time() returns the time the next event is due, in a form
   compatible with the UNIX time() function.

And surely, one would hope that POE supports sub-second accuracy as
documented elsewhere, unlike the explanation above implies. Yet:

   POE::Kernel timers support subsecond accuracy, but don’t expect too
   much here. Perl is not the right language for realtime programming.

... of course, Perl is not the right language to expect sub-second
accuracy - the manpage author must hate Perl to spread so much FUD in
so little space. The Deliantra game server logs with 100µs-accuracy
because Perl is fast enough to require this, and is still able to deliver
map updates with little jitter at exactly the right time. It does not,
however, use POE.

   Furthermore, since the Kernel keeps track of everything sessions do, it
   knows when a session has run out of tasks to perform.

This is impossible - how does the kernel know that a session is no longer
watching for some (external) event (e.g. by some other session)? It
cannot, and therefore this is wrong - but you would be hard pressed to



( run in 1.774 second using v1.01-cache-2.11-cpan-39bf76dae61 )