Consider:
sub long_task { print "Working... ."; my $counter = 0; while ($counter < 1_000_000) { print "\b", substr("|/-\\", $counter % 4); $counter++; } print "\bdone!\n"; }
That's going to take an awful long time. If it's done in a POE program, nothing else will happen until it finishes.
That's not bad in singletasking POE programs, but most people use POE for its multitasking ability. Breaking the loop into event handlers will make it cooperate with other sessions:
sub long_task_start { my ($kernel, $heap) = @_[KERNEL, HEAP]; print "Working... ."; $heap->{counter} = 0; $kernel->yield("long_task_continue"); } sub long_task_continue { my ($kernel, $heap) = @_[KERNEL, HEAP]; if ($heap->{counter} < 1_000_000) { print "\b", substr("|/-\\", $heap->{counter} % 4); $heap->{counter}++; $kernel->yield("long_task_continue"); } else { print "\bdone!\n"; } }
Each event is tied to some code (in this case a subroutine with the same name), so receiving "long_task_continue" is the same as calling &long_task_continue. Unlike with while, though, POE::Kernel is free to dispatch other events between each iteration of the long task's loop.
Breaking the loop up like this will make it a lot slower. Often each iteration will be relatively fast, but the sheer number of iterations makes the whole loop slow. In that case, each "long_task_continue" event could trigger several iterations. Here each "long_task_continue" event triggers a hundred iterations. The entire task should take a more reasonable time to run.
sub long_task_continue { my ($kernel, $heap) = @_[KERNEL, HEAP]; my $timeslice_counter = 0; while ($heap->{counter} < 1_000_000 and $timeslice_counter++ < 100) { print "\b", substr("|/-\\", $heap->{counter} % 4); $heap->{counter}++; } if ($heap->{counter} < 1_000_000) { $kernel->yield("long_task_continue"); } else { print "\bdone!\n"; } }
The number of iterations can be adjusted to balance speed with cooperation.
See also: /Waiting