Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

Accessing POE's delayed event queue

by diotalevi (Canon)
on Jul 06, 2004 at 00:12 UTC ( #371994=perlquestion: print w/ replies, xml ) Need Help??
diotalevi has asked for the wisdom of the Perl Monks concerning the following question:

I read POE::Kernel and POE::Session and didn't see anything to query the kernel about the contents of the event queue. There is a regularly occurring event that only needs to occur when someone is connected to my POE::Component::TCP::Server. My OnConnect event should trigger the delayed event only if it isn't already in the queue. If I just use the normal delayed event dispatching methods then all I can do is clear or add to the delayed event queue.

If there isn't a way to get this from POE then I just have to keep track of whether I've sent a message from outside of POE. I've no problem doing this as an implementation but I don't think it is the right way to do it.

sub event_foo { $_[KERNEL]->delay_if_not_already_queued( $_[SESSION], ... ); } OR sub event_foo { $_[KERNEL]->delay( $_[SESSION], ... ) if not $_[KERNEL]->already_queued( 'event_foo' ); }

Comment on Accessing POE's delayed event queue
Download Code
Re: Accessing POE's delayed event queue
by RMGir (Prior) on Jul 06, 2004 at 16:37 UTC
    Looking at perldoc POE::Kernel, it looks like everything you need is already there.
    Original alarm and delay methods: ... # Post an event which will be delivered after a delay, specif +ied in # seconds hence. This clears previous timed events with the s +ame # name. $kernel->delay( $event, $seconds, @event_args ); # Post an additional delay, leaving existing ones in the queu +e. $kernel->delay_add( $event, $seconds, @event_args ); June 2001 alarm and delay methods: ... # Post an event which will be delivered a number of seconds h +ence. # This does not clear previous events with the same name. $alarm_id = $kernel->delay_set( $event, $seconds_hence, @etc +); ... # Refresh an existing delay to a number of seconds in the fut +ure. $kernel->delay_adjust( $delay_id, $number_of_seconds_hence ); ...
    It looks like you have to use the new _set and _adjust forms, but you can only do adjustments if you saved the id _set returned. Almost looks like you're back to square one :(

Re: Accessing POE's delayed event queue
by rcaputo (Chaplain) on Jul 06, 2004 at 17:02 UTC

    The short answer: POE doesn't have a public method to query the event queue. If it did, the generic "grep the event queue" would be slower than just checking a flag.

    The medium answer: POE::Queue::Array has a generic query mechanism, but POE::Kernel doesn't expose it. Even if it did, searching the queue would be an O(N) operation while maintaining and checking a flag are O(1).

    The long answer:

    POE's event queue is an ordered heap, implemented using a Perl array. It's done this way to make inserting events fast (that's O(N) for small queues and O(log N) for large ones). Removing the next event is always an O(1) operation.

    So POE is optimized for what you do most of the time: Posting events, setting timers, and dequeuing the next event. Actually finding an event in the queue is not optimize, so it's quicker (although more work for you) to manage a flag.

    You could create a small function library to keep track of special one-shot timers, though. Something like this untested code:

    my %pending; sub set_oneshot_timer { my ($event, $hence) = @_; my $session_id = $poe_kernel->get_active_session()->ID(); return if exists $pending{$session_id}{$event}; $poe_kernel->delay( $event, $hence ); $pending{$session_id}{$event} = 1; } sub caught_oneshot_timer { my $event = shift; my $session_id = $poe_kernel->get_active_session()->ID(); delete $pending{$session_id}{$event}; delete $pending{$session_id} unless keys %{$pending{$session_id}}; }

    To use it:

    sub some_event_handler { # set a timer for 10s from now, unless it's already set set_oneshot_timer( event_to_send => 10 ); } sub handle_timer_event { # caught the timer; clear the flag caught_oneshot_timer($_[STATE]); }

    I hope this helps.

    -- Rocco Caputo -

      Thanks. I wrote this as a flag setting/checking operation but didn't think that was the right way to do this. I guess so. Thanks for clarifying the proper practice.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://371994]
Approved by PodMaster
Front-paged by broquaint
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
As of 2014-12-27 18:44 GMT
Find Nodes?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?

    Results (177 votes), past polls