On Apr 28, 2008, at 06:24, Marc Lehmann wrote:
[most important points first]

In your case, I would create a single persistent POE::Session instance
that serviced all the watchers.

I would, too, but I cannot find a way to do that with POE: sessions
without active watchers will be destroyed, forcing the session to have
active resources will make the program never-ending.

I already told you that I tried this approach, and why I couldn't get it
working.

I might use something like an explicit reference count to keep the session alive. I would create a proxy object that, when DESTROYed, would post a shutdown message to the session. Or if AnyEvent knows when a program is to exit, I would have it explicitly shutdown the session as part of its finalization.

The shutdown handler would remove the explicit reference count, allowing the session to stop.

It's similar to the technique you use in AnyEvent::Impl::POE:

sub DESTROY {
   POE::Kernel->post (${${$_[0]}}, "stop");
}

Except it would be done once at the very end, rather than for each event watcher.

Perhaps this isn't necessary. You're not using run(), so technically you're free to go at any time. If your program must exit while watchers are active, then you could force the issue by sending a global UIDESTROY signal (designed to tell POE when it must unconditionally stop), and calling run():

$poe_kernel->signal($poe_kernel, "UIDESTROY");
$poe_kernel->run();

On the other hand, your AnyEvent::Impl::POE proxy objects could also hold references to the singleton session, and if they release those references when they clean up their POE::Kernel resources, the session should be "empty" by the time they all destruct. In that case, the UIDESTROY signal should not be needed. run() will return after removing the "empty" session.

In short, your AnyEvent::Impl::POE objects would be of the form:

sub new {
  # (AnyEvent::Impl::POE setup goes here)
  # set up the POE::Kernel watcher
  $poe_kernel->something(something);
  # make a note of the watcher in this object
  $self->{something} = $record_of_the_poe_watcher;
  return $self;
}

sub DESTROY {
  my $self = shift;
  # ... release the POE::Kernel watcher
  $poe_kernel->something($self->{something}, something);
}

If you expect the user to be creating their own POE::Session instances, then you'd need to call() AnyEvent::Impl::POE to make sure the watchers are created in the right context.

sub new {
  # (AnyEvent::Impl::POE setup goes here)
  # set up the POE::Kernel watcher
  $poe_kernel->call("anyevent_impl_poe", "something", something);
  # make a note of the watcher in this object
  $self->{something} = $record_of_the_poe_watcher;
  return $self;
}

And DESTROY would tell the session when to clear the watcher.

You may need to add a new AnyEvent::Impl method to explicitly stop POE, especially if your public API allows users to exit with active watchers.

sub shutdown {
  $poe_kernel->signal($poe_kernel, "UIDESTROY");
  POE::Kernel->run();
}

As an added bonus, shutting down this way satisfies the run() warning.

I know this isn't a full solution, but I hope you still find it helpful.

You kepe repeating how it could be designed better, but you never actually say how to solve the fundamental problems and bugs within POE that keep it
from being implementable.

I would be welcome to discuss the code more than each-other. If we can agree on this, perhaps we can get down to more important matters. See above.

As I said, if possible, I can only imagine the design becoming vastly more complex because I would have to create sdessions on demand and be able to
react to my session beign turned down at unopportune times.

I don't understand why this design is necessary. Please help me understand your design constraints, so that I may focus on designs that will work.

What we seem to agree on by now is that such a design is not trivial to do
with POE.

Also, remember that the benchmarks show that session creation is not
the big problem, running the sesions is - of course, there could be
inefficiencies in POE handling large number of sessions, but that means
just that - POE doesn't scale well.

While my suggestions are not as trivial as your current design, I don't think the end design will be as complex as you expect.

Thank you for your feedback. I'm sorry that POE doesn't meet your needs. When I have the chance, I'll profile POE while running your benchmark and see what I can do.

As the documentation mentions, AnyEvent doesn't enforce itself on a
module, unlike POE - a module using POE is not going to work with other
event loops, because it monopolises the process.


This means that a module using POE forces all its users to also use POE.

This is factually incorrect. For example, POE::Loop::Glib allows POE to be embedded into applications like vim and irssi. The application's functionality is not impaired, nor is communication between the native scripting elements and the embedded POE code.

POE defers to the native event loop whenever possible. For example, the main loop from POE::Loop::Gtk:

sub loop_run {
  unless (defined $_watcher_timer) {
    $_watcher_timer = Gtk->idle_add(\&_loop_resume_timer);
  }
  Gtk->main;
}

In cases where issues prevent POE from using the native loop, a custom loop is written around the native DoOneEvent() (or equivalent) dispatcher.

This is a fundamental difference between POE and AnyEvent, it has nothing to do with event loop backend modules, of which POE also emplys a few, but
comes form the fact that you have to call POE::Kernel->run and give up
your process to it (just like with EV::loop etc.)

I believe the above loop_run() above shows this to be factually incorrect. Even when POE::Kernel->run() is called, execution is passed back to the native event loop.

AnyEvent::Impl::POE doesn't relinquish control to POE::Kernel->run(), so it seems to conflict with your claim.

On Mon, Apr 28, 2008 at 04:36:42AM -0400, Rocco Caputo <[EMAIL PROTECTED] > wrote:

Are you aware that I'm gradually rewriting POE's documentation?  If
you could describe what you don't like in a useful way, I may be able
to do something about it.

Since I described it already (and you know that) it means you find the way
I did it "not useful". Thats a strawman argument. If you don't like my
criticism or don't understand it, ask.

Okay, I will ask. In all cases, please include sufficient information in your reply so that I can find the documentation in question.

What is inaccurate?  How is it inaccurate?
What parts could I improve?  How could I improve them?
What is missing?
What isn't necessary?
If I've overlooked a question to ask, please let me know, and I will ask it.

It is fine with me if you don't understand AnyEvent, it is somewhat fine
with me if you make strong (But wrong) statements about it, but don't
expect anybody to put much faith in them, or you ability to make useful
statements.

Back at you. See above for some examples where your strong statements against POE have been incorrect.

As I've said before, I'd like to resolve these misunderstandings so that we can move forward in a more amicable and efficient fashion. If we can eventually exhaust our misconceptions by thoroughly addressing them, then perhaps we can move on to more productive things.

Assuming that N is the same between the equivalent POE and
AnyEvent::Impl::POE program:

S(N*M) > S(N) for M > 1.

QED  :P

I couldn't really follow you here, and I am not sure what you have proven. To me it certainly looks as if it was "POE cannot support the AnyEvent API
efficiently" (at leats not in a simple and straightforward way).

I don't know how to be more explicit, unambiguous, and emotionally neutral than by modeling the overhead mathematically. If that's insufficient, then I'm at a loss for how to proceed.

I can only imagine making some very complex on-demand instantiating and
re- check wether the session still exists on each watcher creation.

Your imagination comes up with such incredible things.  Don't lose
that. :)

Overbearing words after being wrong before.

My bad. It's a long message, and I had to let off some steam. On a more positive note, you do have an inventive mind, and I really do hope that you never lose that quality.

I use this design in POE::Stage.

Does it survice multiple run's? If yes, how so?

I'm not sure that multiple run()s is a relevant issue. Your code seems to get along without calling run() at all.

The number of POE::Session instances has no bearing on whether you can continue using loop_do_timeslice().

I am obviously overlooking something. If you could explain what that is, we could put this detail to rest and move on.

(the race condition with sigchld is really annoying,

Please describe the race condition in a useful way, so that I can
investigate and possibly fix it.

Again the red herring "useful" - it obviously was useful enough for other people to understand the issue. The problem is that rgeistering a watcher after the child process already exited causes POE to introduce a delay in reapign the child (it does seem to do polling to do so, and seems to do so once per second, so the delay is at most a second, still, thats a pretty
long time).

[more specifics snipped]

A useful report is one that can be use to replicate or isolate the problem. Saying "the race condition with sigchld" is not useful. Being more specific, as you have just done, is VERY useful. Thank you!

An experimental fix for what you describe has already been released. Because it's experimental, you will need to enable it manually. Please verify you're using the most recent POE, and check POE::Kernel's documentation for "USE_SIGCHLD".

It appears that the sig_child() documentation conflicts with the USE_SIGCHLD documentation. I have fixed it for the next release.

The "run() method was never called" message can be silenced by calling
run().  Not all applications require run().  But if you call it
without any POE::Session instances, it will return immediately and
satisfy POE::Kernel.

This is impossible it guarentee from within AnyEvent.

So there is no way to silence just the message.
[...]
AnyEvent::Impl::POE already invokes the run workaround in its manpage, and why it is undesirable. This puts an unecessary burden on the user, and is
certainly an issue.

Your code already silences this warning, so I don't know why you keep saying it can't be done:

# have to do this to keep POE from spilling ugly messages
POE::Session->create (inline_states => { _start => sub { @_[KERNEL]- >stop } });
POE::Kernel->run;

Unless AnyEvent is doing something I don't know, you should be able to drop the POE::Session->create() line without any harm.

You complain about a message that occurs when a program leaks a child
process.  Programs that leak processes are broken in a way that is
difficult to detect without the warning.  In extreme cases, process
leakage can quietly strangle a machine to death.

No, I complain about the emssage complaining about POE reaping a child. No leak is involved anywhere, and nothign will "quietly" "strangle" anything
to death.

The message I'm thinking of occurs at the end of the program when POE checks whether any child processes remain. Exiting without reaping children is considered bad form and can lead to orphan processes on some systems, so POE enforces this behavior. The warning indicates that the application has not been looking after its children.

POE doesn't reap children unless there is a sig_child() watcher. Therefore, if your program is long-running, spawns processes during its normal operation, and fails to trigger reaping, it will eventually exhaust its process resources.

If the application runs as root, there will often be no ulimit guard preventing zombie processes from filling up the system's process table. If this happens, the system will most likely become unresponsive and need to be restarted.

I consider such applications to be broken. You are welcome to think otherwise, but POE will continue to point out when this happens.

The most direct solution is for an application to set sig_child() handlers for the children it creates. This will trigger reaping, and the warnings (and potential for catastrophe) will go away.

OMG, we agree on something!  The end times are here:


sorry?

It's a joke. You see, we agree on so little, so actually agreeing on something is a momentous event. I was humorously drawing parallels to events that signal the impending end of the world in some religions. The "end times" are also conveniently where I finished my e-mail. It's a bit of a pun, really.

--
Rocco Caputo - [EMAIL PROTECTED]

Reply via email to