The difference is very favorable, here are my benchmark results:
POE::Kernel->call(): 123 wallclock secs (111.82 usr + 0.86 sys = 112.68 CPU) @ 8874.69/s (n=1000000)
POE::Kernel->invoke(): 33 wallclock secs (28.74 usr + 0.05 sys = 28.79 CPU) @ 34734.28/s (n=1000000)
Attached is the benchmark code used, the debug output from make test, and the patchset.
All tests successful, 12 subtests skipped.
Files=40, Tests=3171, 115 wallclock secs (23.17 cusr + 0.84 csys = 24.01 CPU)
The name of the invoke method has been one of mild controversey, I've been told it sounds too much like call(). The meaning of invoke isn't different enough for one to neccesarily expect people to make the mental seperation between their behavior. I decided to keep the name upon submitting the patch to the mailing list for two reasons. The first reason is that I dont neccesarily agree with those arguements, the second reason is I have yet to come up with a better name for what it does. If anyone has a suggestion that the majority agrees is a better name for the method, I'll gladly change the patch and resubmit.
test-output.err: Debug output from make test on my tree test_invoke.pl: Benchmark for testing invoke() state POE-Kernel.patch: Patchset for lib/POE/Kernel.pm POE-Wheel.patch: Patchset for lib/POE/Wheel/
- Scott
<ev> enqueued event 1 ``_stat_tick'' from session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) to session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) at 1077161482.95295 at lib/POE/Resource/Events.pm line 72 <rc> incrementing refcount for session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) at lib/POE/Resource/Sessions.pm line 353 <rc> incrementing refcount for session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) at lib/POE/Resource/Sessions.pm line 353 <ev> enqueued event 2 ``_sigchld_poll'' from session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) to session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) at 1077161453.95505 at lib/POE/Resource/Events.pm line 72 <rc> incrementing refcount for session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) at lib/POE/Resource/Sessions.pm line 353 <rc> incrementing refcount for session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) at lib/POE/Resource/Sessions.pm line 353 <ss> session 2 (POE::Session=ARRAY(0x83f1d8c)) has parent session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) at lib/POE/Resource/Sessions.pm line 90 <rc> incrementing refcount for session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) at lib/POE/Resource/Sessions.pm line 353 <ss> session 3 (POE::Session=ARRAY(0x8174cc0)) has parent session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) at lib/POE/Resource/Sessions.pm line 90 <rc> incrementing refcount for session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) at lib/POE/Resource/Sessions.pm line 353 <sg> stopping signaled session session 3 (POE::Session=ARRAY(0x8174cc0)) at lib/POE/Resource/Signals.pm line 262 <ss> stopping session 3 (POE::Session=ARRAY(0x8174cc0)) at lib/POE/Resource/Sessions.pm line 461 <ev> Dispatching event -494 ``_child'' (lose POE::Session=ARRAY(0x8174cc0)) from session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) to session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) at lib/POE/Kernel.pm line 694 <ev> dispatching event -494 ``_child'' to session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) at lib/POE/Kernel.pm line 824 <ev> event -494 ``_child'' returns (0) <ev> Dispatching event -503 ``_stop'' () from session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) to session 3 (POE::Session=ARRAY(0x8174cc0)) at lib/POE/Kernel.pm line 694 <ev> dispatching event -503 ``_stop'' to session 3 (POE::Session=ARRAY(0x8174cc0)) at lib/POE/Kernel.pm line 824 <ev> event -503 ``_stop'' returns (undef) <ss> freeing session 3 (POE::Session=ARRAY(0x8174cc0)) at lib/POE/Resource/Sessions.pm line 114 <ss> removed session 3 (POE::Session=ARRAY(0x8174cc0)) from session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) at lib/POE/Resource/Sessions.pm line 150 POE::Kernel::_data_ses_free('POE::Kernel=ARRAY(0x833da9c)','POE::Session=ARRAY(0x8174cc0)') called at lib/POE/Resource/Sessions.pm line 507 POE::Kernel::_data_ses_stop('POE::Kernel=ARRAY(0x833da9c)','POE::Session=ARRAY(0x8174cc0)') called at lib/POE/Resource/Signals.pm line 269 POE::Kernel::_data_sig_free_terminated_sessions('POE::Kernel=ARRAY(0x833da9c)') called at t/res/signals.t line 254 <rc> decrementing refcount for session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) at lib/POE/Resource/Sessions.pm line 322 <rc> testing for idle session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) at lib/POE/Resource/Sessions.pm line 381 <rc> +----- GC test for session asus-40342dec00000de2 (POE::Kernel=ARRAY(0x833da9c)) (POE::Kernel=ARRAY(0x833da9c)) ----- <rc> | total refcnt : 5 <rc> | event count : 2 <rc> | post count : 2 <rc> | child sessions: 1 <rc> | handles in use: 0 <rc> | aliases in use: 0 <rc> | extra refs : 0 <rc> +--------------------------------------------------- ----- Session POE::Session=ARRAY(0x8174cc0) Leak Check ----- -- Namespace (HEAP): $VAR1 = undef; -- Options: -- States: ----- Session POE::Session=ARRAY(0x83f1d8c) Leak Check ----- -- Namespace (HEAP): $VAR1 = undef; -- Options: -- States:
#!/usr/bin/perl -l
use warnings FATAL => "all"; use strict; use POE; use Benchmark; create POE::Session inline_states => { _start => sub { $_[KERNEL]->yield("StartTest"); }, StartTest => sub { my ($kernel, $session) = @_[ KERNEL, SESSION ]; timethese 1_000_000, { "POE::Kernel->invoke()" => sub { $kernel->invoke("Tick"); }, "POE::Kernel->call()" => sub { $kernel->call($session, "Tick"); }, }; }, Tick => sub { "Boink!"; }, }; run POE::Kernel;
--- poe/lib/POE/Kernel.pm 2004-02-11 00:28:28.000000000 -0800 +++ poe.kernel.invoke/lib/POE/Kernel.pm 2004-02-18 19:12:30.000000000 -0800 @@ -1469,6 +1469,24 @@ return $return_value; } +sub invoke { + my ($file, $line, $self, $state, @etc) = ((caller)[1,2], @_); + + my $return; + if (wantarray) { + $return = [ $kr_active_session->_invoke_state + ( $kr_active_session, $state, [EMAIL PROTECTED], $file, $line ) ]; + } + else { + $return = $kr_active_session->_invoke_state + ( $kr_active_session, $state, [EMAIL PROTECTED], $file, $line ); + } + + return $return unless wantarray; + return @$return; +} + + #------------------------------------------------------------------------------ # Peek at pending alarms. Returns a list of pending alarms. This # function is deprecated; its lack of documentation is by design. @@ -2579,7 +2597,7 @@ status is returned in $!, which is 0 for success or a nonzero reason for failure. - $return_value = $kernel->call( 'do_this_now' ); + $return_value = $kernel->call($_[SESSION], 'do_this_now' ); die "could not do_this_now: $!" if $!; POE uses call() to dispatch some resource events without FIFO latency. @@ -2592,6 +2610,22 @@ ESRCH: The SESSION did not exist at the time call() was called. +=item invoke EVENT_NAME, PARAMETER_LIST + +=item invoke EVENT_NAME + +invoke() bypasses the FIFO as well as the garbage collection and +context switching that call() requires. This is an optimization for +events that exist in the current session, as well as short hand. Its +considerably faster than call() but disallows inter-session state +invocation. Has the same return contexts as call(). + + $return_value = $kernel->invoke("some_event"); + +Invoke is designed specifically for routing time critical events +with in the current session, and is optimized for use with wheels +and other embedded objects. + =back =head2 Delayed Events (Original Interface)
Common subdirectories: poe/lib/POE/Wheel/CVS and poe.kernel.invoke/lib/POE/Wheel/CVS diff -u poe/lib/POE/Wheel/Curses.pm poe.kernel.invoke/lib/POE/Wheel/Curses.pm --- poe/lib/POE/Wheel/Curses.pm 2003-11-20 21:08:26.000000000 -0800 +++ poe.kernel.invoke/lib/POE/Wheel/Curses.pm 2004-02-18 19:15:04.000000000 -0800 @@ -96,7 +96,7 @@ # determined that STDIN has something for us. Be explicit # about which getch() to use. while ((my $keystroke = Curses::getch) ne '-1') { - $k->call( $me, $$event_input, $keystroke, $unique_id ); + $k->invoke( $$event_input, $keystroke, $unique_id ); } } ); diff -u poe/lib/POE/Wheel/FollowTail.pm poe.kernel.invoke/lib/POE/Wheel/FollowTail.pm --- poe/lib/POE/Wheel/FollowTail.pm 2004-01-28 15:19:11.000000000 -0800 +++ poe.kernel.invoke/lib/POE/Wheel/FollowTail.pm 2004-02-18 19:15:36.000000000 -0800 @@ -257,7 +257,7 @@ TRACE_POLL and warn time . " raw input"; foreach my $cooked_input (@{$filter->get($raw_input)}) { TRACE_POLL and warn time . " cooked input"; - $k->call($ses, $$event_input, $cooked_input, $unique_id); + $k->invoke($$event_input, $cooked_input, $unique_id); } } } @@ -268,7 +268,7 @@ if ($! or (-S $handle) or (-t $handle)) { TRACE_POLL and warn time . " error: $!"; $$event_error and - $k->call($ses, $$event_error, 'read', ($!+0), $!, $unique_id); + $k->invoke($$event_error, 'read', ($!+0), $!, $unique_id); $k->select($handle); } eval { IO::Handle::clearerr($handle) }; # could be a globref @@ -326,7 +326,7 @@ # File shrank. Consider it a reset. Seek to the top of # the file. if ($new_stat[7] < $last_stat->[7]) { - $$event_reset and $k->call($ses, $$event_reset, $unique_id); + $$event_reset and $k->invoke($$event_reset, $unique_id); sysseek($handle, 0, SEEK_SET); } @@ -357,7 +357,7 @@ close $handle; unless (open $handle, "<$filename") { $$event_error and - $k->call( $ses, $$event_error, 'reopen', + $k->invoke( $$event_error, 'reopen', ($!+0), $!, $unique_id ); } @@ -375,7 +375,7 @@ TRACE_POLL and warn time . " raw input\n"; foreach my $cooked_input (@{$filter->get($raw_input)}) { TRACE_POLL and warn time . " cooked input\n"; - $k->call($ses, $$event_input, $cooked_input, $unique_id); + $k->invoke($$event_input, $cooked_input, $unique_id); } } $k->yield($state_read); @@ -387,7 +387,7 @@ if ($!) { TRACE_POLL and warn time . " error: $!\n"; $$event_error and - $k->call($ses, $$event_error, 'read', ($!+0), $!, $unique_id); + $k->invoke($$event_error, 'read', ($!+0), $!, $unique_id); $k->select($handle); } $k->delay($state_read, $poll_interval); diff -u poe/lib/POE/Wheel/ListenAccept.pm poe.kernel.invoke/lib/POE/Wheel/ListenAccept.pm --- poe/lib/POE/Wheel/ListenAccept.pm 2003-11-25 19:52:07.000000000 -0800 +++ poe.kernel.invoke/lib/POE/Wheel/ListenAccept.pm 2004-02-18 19:15:49.000000000 -0800 @@ -115,11 +115,11 @@ my $peer = accept($new_socket, $handle); if ($peer) { - $k->call($me, $$event_accept, $new_socket, $peer, $unique_id); + $k->invoke($$event_accept, $new_socket, $peer, $unique_id); } elsif ($! != EWOULDBLOCK) { $$event_error && - $k->call($me, $$event_error, 'accept', ($!+0), $!, $unique_id); + $k->invoke($$event_error, 'accept', ($!+0), $!, $unique_id); } } ); diff -u poe/lib/POE/Wheel/ReadWrite.pm poe.kernel.invoke/lib/POE/Wheel/ReadWrite.pm --- poe/lib/POE/Wheel/ReadWrite.pm 2004-01-24 17:54:58.000000000 -0800 +++ poe.kernel.invoke/lib/POE/Wheel/ReadWrite.pm 2004-02-18 19:16:45.000000000 -0800 @@ -206,7 +206,7 @@ # When you can't write, nothing else matters. if ($!) { - $$event_error && $k->call( $me, $$event_error, + $$event_error && $k->invoke( $$event_error, 'write', ($!+0), $!, $unique_id ); $k->select_write($handle); @@ -222,7 +222,7 @@ if ($$is_in_high_water_state) { if ( $$driver_buffered_out_octets <= $low_mark ) { $$is_in_high_water_state = 0; - $k->call( $me, $$event_low, $unique_id ) if defined $$event_low; + $k->invoke( $$event_low, $unique_id ) if defined $$event_low; } } @@ -236,7 +236,7 @@ ( $$driver_buffered_out_octets >= $high_mark ) ) { $$is_in_high_water_state = 1; - $k->call( $me, $$event_high, $unique_id ) if defined $$event_high; + $k->invoke( $$event_high, $unique_id ) if defined $$event_high; } } @@ -246,7 +246,7 @@ # is 1). unless ($$driver_buffered_out_octets) { $k->select_pause_write($handle); - $$event_flushed && $k->call($me, $$event_flushed, $unique_id); + $$event_flushed && $k->invoke($$event_flushed, $unique_id); } } ); @@ -299,13 +299,13 @@ my $next_rec = $$input_filter->get_one(); last unless @$next_rec; foreach my $cooked_input (@$next_rec) { - $k->call($me, $$event_input, $cooked_input, $unique_id); + $k->invoke($$event_input, $cooked_input, $unique_id); } } } else { $$event_error and - $k->call( $me, $$event_error, 'read', ($!+0), $!, $unique_id ); + $k->invoke( $$event_error, 'read', ($!+0), $!, $unique_id ); $k->select_read($handle); } } @@ -327,12 +327,12 @@ my ($k, $me, $handle) = @_[KERNEL, SESSION, ARG0]; if (defined(my $raw_input = $driver->get($handle))) { foreach my $cooked_input (@{$$input_filter->get($raw_input)}) { - $k->call($me, $$event_input, $cooked_input, $unique_id); + $k->invoke($$event_input, $cooked_input, $unique_id); } } else { $$event_error and - $k->call( $me, $$event_error, 'read', ($!+0), $!, $unique_id ); + $k->invoke( $$event_error, 'read', ($!+0), $!, $unique_id ); $k->select_read($handle); } } @@ -478,8 +478,7 @@ my $next_rec = $self->[FILTER_INPUT]->get_one(); last unless @$next_rec; foreach my $cooked_input (@$next_rec) { - $poe_kernel->call( $poe_kernel->get_active_session(), - $self->[EVENT_INPUT], + $poe_kernel->invoke( $self->[EVENT_INPUT], $cooked_input, $self->[UNIQUE_ID] ); } @@ -491,8 +490,7 @@ else { if (defined $buf) { foreach my $cooked_input (@{$self->[FILTER_INPUT]->get($buf)}) { - $poe_kernel->call( $poe_kernel->get_active_session(), - $self->[EVENT_INPUT], + $poe_kernel->invoke( $self->[EVENT_INPUT], $cooked_input, $self->[UNIQUE_ID] ); } diff -u poe/lib/POE/Wheel/Run.pm poe.kernel.invoke/lib/POE/Wheel/Run.pm --- poe/lib/POE/Wheel/Run.pm 2004-01-28 15:19:13.000000000 -0800 +++ poe.kernel.invoke/lib/POE/Wheel/Run.pm 2004-02-18 19:14:46.000000000 -0800 @@ -512,7 +512,7 @@ # When you can't write, nothing else matters. if ($!) { - $$error_event && $k->call( $me, $$error_event, + $$error_event && $k->invoke( $$error_event, 'write', ($!+0), $!, $unique_id, "STDIN" ); $k->select_write($handle); @@ -525,7 +525,7 @@ # All chunks written; fire off a "flushed" event. unless ($$stdin_octets) { $k->select_pause_write($handle); - $$stdin_event && $k->call($me, $$stdin_event, $unique_id); + $$stdin_event && $k->invoke($$stdin_event, $unique_id); } } } @@ -577,17 +577,17 @@ my $next_rec = $stdout_filter->get_one(); last unless @$next_rec; foreach my $cooked_input (@$next_rec) { - $k->call($me, $$stdout_event, $cooked_input, $unique_id); + $k->invoke($$stdout_event, $cooked_input, $unique_id); } } } else { $$error_event and - $k->call( $me, $$error_event, + $k->invoke( $$error_event, 'read', ($!+0), $!, $unique_id, 'STDOUT' ); unless (--$$is_active) { - $k->call( $me, $$close_event, $unique_id ) + $k->invoke( $$close_event, $unique_id ) if defined $$close_event; } $k->select_read($handle); @@ -608,16 +608,16 @@ my ($k, $me, $handle) = @_[KERNEL, SESSION, ARG0]; if (defined(my $raw_input = $driver->get($handle))) { foreach my $cooked_input (@{$stdout_filter->get($raw_input)}) { - $k->call($me, $$stdout_event, $cooked_input, $unique_id); + $k->invoke($$stdout_event, $cooked_input, $unique_id); } } else { $$error_event and - $k->call( $me, $$error_event, + $k->invoke( $$error_event, 'read', ($!+0), $!, $unique_id, 'STDOUT' ); unless (--$$is_active) { - $k->call( $me, $$close_event, $unique_id ) + $k->invoke( $$close_event, $unique_id ) if defined $$close_event; } $k->select_read($handle); @@ -673,17 +673,17 @@ my $next_rec = $stderr_filter->get_one(); last unless @$next_rec; foreach my $cooked_input (@$next_rec) { - $k->call($me, $$stderr_event, $cooked_input, $unique_id); + $k->invoke($$stderr_event, $cooked_input, $unique_id); } } } else { $$error_event and - $k->call( $me, $$error_event, + $k->invoke( $$error_event, 'read', ($!+0), $!, $unique_id, 'STDERR' ); unless (--$$is_active) { - $k->call( $me, $$close_event, $unique_id ) + $k->invoke( $$close_event, $unique_id ) if defined $$close_event; } $k->select_read($handle); @@ -704,16 +704,16 @@ my ($k, $me, $handle) = @_[KERNEL, SESSION, ARG0]; if (defined(my $raw_input = $driver->get($handle))) { foreach my $cooked_input (@{$stderr_filter->get($raw_input)}) { - $k->call($me, $$stderr_event, $cooked_input, $unique_id); + $k->invoke($$stderr_event, $cooked_input, $unique_id); } } else { $$error_event and - $k->call( $me, $$error_event, + $k->invoke( $$error_event, 'read', ($!+0), $!, $unique_id, 'STDERR' ); unless (--$$is_active) { - $k->call( $me, $$close_event, $unique_id ) + $k->invoke( $$close_event, $unique_id ) if defined $$close_event; } $k->select_read($handle); @@ -898,8 +898,7 @@ my $next_rec = $old_output_filter->get_one(); last unless @$next_rec; foreach my $cooked_input (@$next_rec) { - $poe_kernel->call( $poe_kernel->get_active_session(), - $self->[EVENT_STDOUT], + $poe_kernel->invoke( $self->[EVENT_STDOUT], $cooked_input, $self->[UNIQUE_ID] ); } @@ -909,8 +908,7 @@ # Otherwise use the old get() behavior. else { foreach my $cooked_input (@{$self->[FILTER_STDOUT]->get($buf)}) { - $poe_kernel->call( $poe_kernel->get_active_session(), - $self->[EVENT_STDOUT], + $poe_kernel->invoke( $self->[EVENT_STDOUT], $cooked_input, $self->[UNIQUE_ID] ); } @@ -940,8 +938,7 @@ my $next_rec = $old_output_filter->get_one(); last unless @$next_rec; foreach my $cooked_input (@$next_rec) { - $poe_kernel->call( $poe_kernel->get_active_session(), - $self->[EVENT_STDERR], + $poe_kernel->invoke( $self->[EVENT_STDERR], $cooked_input, $self->[UNIQUE_ID] ); } @@ -951,8 +948,7 @@ # Otherwise use the old get() behavior. else { foreach my $cooked_input (@{$self->[FILTER_STDERR]->get($buf)}) { - $poe_kernel->call( $poe_kernel->get_active_session(), - $self->[EVENT_STDERR], + $poe_kernel->invoke( $self->[EVENT_STDERR], $cooked_input, $self->[UNIQUE_ID] ); } diff -u poe/lib/POE/Wheel/SocketFactory.pm poe.kernel.invoke/lib/POE/Wheel/SocketFactory.pm --- poe/lib/POE/Wheel/SocketFactory.pm 2003-11-25 19:52:07.000000000 -0800 +++ poe.kernel.invoke/lib/POE/Wheel/SocketFactory.pm 2004-02-18 19:17:21.000000000 -0800 @@ -204,14 +204,14 @@ else { die "sanity failure: socket domain == $domain"; } - $k->call( $me, $$event_success, + $k->invoke( $$event_success, $new_socket, $peer_addr, $peer_port, $unique_id ); } elsif ($! != EWOULDBLOCK) { $$event_failure && - $k->call( $me, $$event_failure, + $k->invoke( $$event_failure, 'accept', ($!+0), $!, $unique_id ); } @@ -271,7 +271,7 @@ $! = unpack('i', getsockopt($handle, SOL_SOCKET, SO_ERROR)); if ($!) { (defined $$event_failure) and - $k->call( $me, $$event_failure, + $k->invoke( $$event_failure, 'connect', ($!+0), $!, $unique_id ); return; @@ -281,7 +281,7 @@ my $peer = getpeername($handle); if ($!) { (defined $$event_failure) and - $k->call( $me, $$event_failure, + $k->invoke( $$event_failure, 'getpeername', ($!+0), $!, $unique_id ); return; @@ -330,7 +330,7 @@ } # Tell the session it went okay. Also let go of the socket. - $k->call( $me, $$event_success, + $k->invoke( $$event_success, $handle, $peer_addr, $peer_port, $unique_id ); } @@ -361,7 +361,7 @@ $! = unpack('i', getsockopt($handle, SOL_SOCKET, SO_ERROR)); if ($!) { (defined $$event_failure) and - $k->call( $me, $$event_failure, + $k->invoke( $$event_failure, 'connect', ($!+0), $!, $unique_id ); return;