[Chicago-talk] Which "if" structure is faster?

Steven Lembark lembark at wrkhors.com
Mon Feb 23 23:23:07 CST 2004


> 	my $sub = 0;
>
> 	my $after =
> 	sub
> 	{
> 		remaining_passes @remaining_args;
>
> 		# returns nonzero on completion
>
> 		$finished
> 	};
>
> 	my $prior =
> 	sub
> 	{
> 		first_pass @first_time_args;
> 		$sub = $after;
> 	};
>
> 	...
>
> 	# no if logic required: the first pass through the
> 	# closure calls do_soemthing and then updates the
> 	# reference variable to call the after-the-fisrt-pass.
> 	#
> 	# these could be the same sub with different args or
> 	# two different subs: the infinite loop exits whenever
> 	# the $after closure returns true.
>
> 	for(;;) { $sub->() && last }

Follow up: One common issue is the setup -> first pass ->
process -> cleanup cycle. If-logic slows this down quite
a bit during the execution. It also complicates things
due to state variables and the added if-logic used to
check them.

Easier way out:

	package Frobnicate;

	my $sub = 0;

	my @handlerz =
	(
		sub
		{
			# initialize inputs, etc.
			# this doesn't read any input, it just initializes
			# the input stream and passes off the real work to
			# the first record handler (or whatever follows it
			# in the handler stack).

			...

			$sub = shift @handlerz;
		},

		sub
		{
			# handle the first record.
			# note that this may be expensive, and is
			# worth putting off until a record that
			# requires handling is available. good
			# example of this are DBI connections w/in
			# mod_perl: having all of the forked handlers
			# initate DBI connections at once can be
			# painful; this puts off the real work until
			# the apache process actually handles something.
			#
			# this can also be useful for XML processing,
			# there the prior handler did nothing more than
			# include Perl::SAX, this can generate a full
			# grammer from a schema, and then hand off input
			# to the main data stream to the next processor.
			#
			# after doing its work this passes off control
			# to the "normal" record handler.

			...

			$sub = shift @handlerz;
		},

		sub
		{
			# handle records until an end of stream is
			# detected -- which may be never, which case
			# the if at the end here is unnecessary.

			...

			$sub = shift @handlers if $finished
		},

		sub
		{
			# tear down any structures, clean up, and
			# exit the handler. this will never be
			# called if the prior loop never updates
			# $sub. this stops the for loop since it
			# returns false -- indicating the end of
			# stream has been detected.

			...

			0
		}
	);

	sub handler_stack { \@handlerz };

	...

	package Foo::Bar;

	# main input loop keeps going until the handler
	# returns false.

	my $handler_class = shift; # whatever...

	eval "use $handler_class";

	my $get_stack = $handler_class->can( 'handler_stack' )
		or die "Bogus handler class: $handler_class cannot 'handler_stack'";

	my $handlerz = $handler_class->$get_stack->()
		or die "Bogus handler class: $handler_class returns false stack";

	for( my $sub = shift @handlerz ; $sub->() ; ) {}


Nice thing about this is that you can choose the handler
stack class at runtime (via config file or command line)
and the dispatcher has no idea what is really going on.
All it does is call handlers until they return false.

enjoi

--
Steven Lembark                               2930 W. Palmer
Workhorse Computing                       Chicago, IL 60647
                                            +1 888 359 3508



More information about the Chicago-talk mailing list