POE Supports Other Event Loops, Really

rcaputo on 2009-09-11T05:57:26

Lately I've been hearing, repeatedly and loudly, that POE doesn't work with other event loops. I wrote the first bridge between POE and another event loop in May of 2000, so this is rather shocking news to me. I've had to rerun "make test" just to be sure I wasn't dreaming! :)

Here is a slightly edited repost of my reply to Tatsuhiko Miyagawa, who writes in regards to his YAPC::Asia presentation:

Rocco, the author of POE pointed out that slides 19-21 are misleading since POE also has the POE::Loop concept so that you can run your event loop under different backends like EV or Gtk. While that is true (and that is great), POE still can't run with the other main loop, like IO::Async::Loop->loop_forever. You still need to call POE::Kernel->run and to do so you should rewrite your main program to use POE everywhere, since existent IO::Async based program can't run any of POE::Component, which is totally possible with AnyEvent and AnyEvent::* modules.

I respectfully disagree, and I have code to back me up.

POE runs with other main loops. In fact, POE::Kernel->run() is often implemented in terms of native event dispatchers. POE::Loop classes implement event watchers using native watchers, and native callbacks are used to generate POE events. Your call to $kernel->select_read() becomes Event->io(), Gtk::Gdk->input_add(), etc.

Depending on the POE::Loop implementation, POE::Kernel->run() need not be called upon to dispatch events. This is CPAN, so your mileage may vary. If you're interested in improving CPAN, submit bug reports to the appropriate queues.

I mentioned I had code. Here's a working example of POE code and native Glib code running together in the same program, using Glib's MainLoop:

use Glib; # Install POE::Loop::Glib.
use POE;

POE::Session->create(
  inline_states => {
    _start => sub { $_[KERNEL]->delay(tick => 1) },
    tick => sub {
      print "poe tick at ", time(), "...\n";
      $_[KERNEL]->delay(tick => 1);
    },
  },
);

my $glib_timer = Glib::Timeout->add(
  500, sub {
    print "glib tick at ", time(), "...\n";
    return 1;
  }
);

# Dispatches Glib and POE events.
Glib::MainLoop->new->run();

Of course you can call POE::Kernel->run() instead of Glib's main loop. This is a good thing. A single, portable run() method covers every supported event loop.

Addendum:

Things get really interesting when you realize that POE can be loaded into event loops that are already running. For example, Martijn van Beers and Chris Williams have been running POE inside irssi for years. Chris has even embedded an entire POE-based IRC server in irssi, which got a little mind-bendy when he connected to irssi from itself. Both cases work without rewriting irssi's main program.


Thanks

awwaiid on 2009-09-14T15:19:29

Thanks for this example, I find it clarifies the run-loop conflict (or lack thereof) quite clearly.

--Brock