Hi! I used Event for many, many years, and, while its easily the best event loop out there, I had a number of issues with it (mostly scalability and bugs that the not-very-active maintainer doesn't fix, but also performance problems and specific limitations for my uses).
Recently I set out to write an interface to libevent, but since it had the same kind of artificial limitations and bugs as Tk (which has about the worst event loop possible :), I created my own replacement for libevent called libev, and based my perl module on it (it also beats libevent hands-down, see http://libev.schmorp.de/bench.html). The perl interface to libev is called EV, is on CPAN, and is of course not yet as mature as Event, but is used in production already in some commercial apps, the deliantra game server (and the underlying libev library is used in the gnu virtual private ethernet and rxvt-unicode packages). It supports select, poll, epoll, kqueue (on the few platforms where it works, i.e. "netbsd only") and solaris ports as backends. Documentation for the perl module: http://cvs.schmorp.de/EV/README Documentation for libev library: http://cvs.schmorp.de/libev/ev.html All this is something I wanted to do for many years, but the effort required kept me from doing it (originally I wanted to take Event and improve it, it being the best event loop after all, but this didn't turn out to be reasonable, for example, changing watcher lifetime semantics would obvioously not be reasonable). Here is a partial list of (perceived or real) problems or lacks of features that EV improves upon over Event: - watcher creation is very fast (about 25 times(!) faster than with Event), making it feasible to create and tear down watchers quickly. I measured creating and destroying a timer with EV, AnyEvent+EV, Event and Glib, and also compared to just using $ev_timer->set+start (EV_set). AnyEvent: 3 wallclock secs ( 3.09 usr + 0.00 sys = 3.09 CPU) @ 323624.60/s (n=1000000) EV: 0 wallclock secs ( 0.95 usr + 0.00 sys = 0.95 CPU) @ 1052631.58/s (n=1000000) EV_set: 0 wallclock secs ( 0.36 usr + 0.00 sys = 0.36 CPU) @ 2777777.78/s (n=1000000) Event: 40 wallclock secs (39.61 usr + 0.01 sys = 39.62 CPU) @ 25239.78/s (n=1000000) Glib: 3 wallclock secs ( 3.66 usr + 0.01 sys = 3.67 CPU) @ 272479.56/s (n=1000000) - EV watchers are normal perl objects, no need for explicit destruction (this is slightly inconvinient for unrealistically simple programs, but much simpler for real-world cases). - it copes with timejumps, both forward and backward (how well it does that depends on the availability of a monotonic clock, but it copes even in its absence). - it has usable "hard realtime" timers (the hard realtime timers in Event will go into an almost endless loop on timejumps and other delays and make them completely useless, as you have to implement your own scheduling anyways to make them usable). - it separates timers into timers based on wallclock time ("periodics") and timers based on real time. The former is good for cron-like timers, the latter is good for delays and timeouts. The fact that you cannot do either with Event always made me uneasy, and also ruled out Event usage in some very important use cases, as freezes due to ntp clock resets are unacceptable sometimes. - all operations are either O(1) or O(log n), not O(n) (n = #watchers) or worse as in Event. If you have a lot of timers or I/O watchers this makes an extreme difference, as Event walks its timer and I/O list on every poll call, while in libev, this operation is O(1). - It uses *much* less memory per watcher than Event (honestly, I never saw that as a problem with Event, but in big programs, it made a very noticable difference in ps output). - there cannot be endless resource overflow (the event loop in Event can grow endlessly without ever having a chance to reduce its size, freezing the program on certain conditions). This is a real big problem with Event, which basically makes its priority system useless. - the main loop is reentrant w.r.t. coroutines. - it has support for child process status change events. - EV is much more parsimonous of system calls. - events have timestamps (at no additional cost. This is useful for more exact scheduling of timeouts for example, or simply to see by how much event processing is delayed). - the design is still open to some discussion and feature requests, so feel free to ask for things and I might be able to provide them. It also has a full-featured C API (which Event also has, but some of the quirks that made it hard to use are gone), delivering the full libev API to any extensions. AnyEvent is fully supported (ok, this is not surprising, being from the same author), so modules using AnyEvent can take advantage of it without thinking a second. I also tried to preserve all the good things about Event (which after all, was my Event module of choice for almost a decade), and decided that sharing EV with everybody else might be helpful to some. I hope thats true. (Some of the good things in Event are purely ingenious, for example, the check and prepare hooks, which allow easy integration of many C and Perl libraries into Event, something which I have not yet seen in other event loop implementations, but which I think are absolutely essential. Event has a number of those concepts not found elsewhere that make it very mature and general). EV is available on CPAN, its homepage is linked from http://libev.schmorp.de. To give you an impression of how the API looks like, here are some examples from the manpage: # TIMERS my $w = EV::timer 2, 0, sub { warn "is called after 2s"; }; my $w = EV::timer 2, 2, sub { warn "is called roughly every 2s (repeat = 2)"; }; undef $w; # destroy event watcher again my $w = EV::periodic 0, 60, 0, sub { warn "is called every minute, on the minute, exactly"; }; # IO my $w = EV::io *STDIN, EV::READ, sub { my ($w, $revents) = @_; # all callbacks receive the watcher and event mask warn "stdin is readable, you entered: ", <STDIN>; }; # SIGNALS my $w = EV::signal ’QUIT’, sub { warn "sigquit received\n"; }; # CHILD/PID STATUS CHANGES my $w = EV::child 666, sub { my ($w, $revents) = @_; my $status = $w->rstatus; }; # MAINLOOP EV::loop; # loop until EV::unloop is called or all watchers stop EV::loop EV::LOOP_ONESHOT; # block until at least one event could be handled EV::loop EV::LOOP_NONBLOCK; # try to handle same events, but do not block And here is a rough example of how to integrate e.g. Net::SNMP, by registering a prepare (called before blocking) and check (called after blocking) watcher to create and tear down watchers for the sockets Net::SNMP uses as well as the timeout it needs: our @snmp_watcher; our $snmp_prepare = EV::prepare sub { # do nothing unless active $dispatcher->{_event_queue_h} or return; # make the dispatcher handle any outstanding stuff ... not shown # create an IO watcher for each and every socket @snmp_watcher = ( (map { EV::io $_, EV::READ, sub { } } keys %{ $dispatcher->{_descriptors} }), EV::timer +($event->[Net::SNMP::Dispatcher::_ACTIVE] ? $event->[Net::SNMP::Dispatcher::_TIME] - EV::now : 0), 0, sub { }, ); }; our $snmp_check = EV::check sub { # destroy all watchers @snmp_watcher = (); # make the dispatcher handle any new stuff ... not shown }; Thanks for your consideration. -- The choice of a Deliantra, the free code+content MORPG -----==- _GNU_ http://www.deliantra.net ----==-- _ generation ---==---(_)__ __ ____ __ Marc Lehmann --==---/ / _ \/ // /\ \/ / [EMAIL PROTECTED] -=====/_/_//_/\_,_/ /_/\_\