Trivial non-local-returns efficiency question

Ken Manheimer (ken.manheimer@nist.gov)
Fri, 23 Sep 94 12:55:26 EDT

I have a niggling little question that isn't really important in this
particular case, but i figure it's worth investigating for future
ref...

I'm building a simple python routine to scan a db and obtain qualified
records. The routine needs to do some cleanup on conclusion.

The routine entails a loop with an embedded loop that has one of the
conclusion conditions, so i am considering using 'return' from the
embedded loop, caught by 'try'/'finally' around the containing loop
to do the cleanup. (Since the real return can come from more than one
place, i would have the finally do the real return, making the
overhead of the embedded return extra expense.)

I'm also considering using a var within the embedded condition to
convey the conclusion cue, and have the containing loop check the
conclusion var each cycle, to determine whether it's finished.

My hesitation on using the 'return' for a non-local exit from the
containing loop is because i'm not sure whether or not 'return', even
when caught, entails lots of overhead. The question is, what's the
overhead on a return that's caught by a 'finally', and how long does
it take to chalk up equivalent overhead on an additional loop
condition in the encompassing loop?

Here's the two alternatives:

-- Using return, caught by finally:

try:
while 1:
got.append(rec)
rec = self.db.search(metalbase.NEXT, rec)
if rec: # Validate new rec:
for key, val in pairs:
if getattr(rec, key) != val:
# Done once we're past ordered index recs:
return # 'Finally' will return real val #=v
else: # Got to very end:
break # 'Finally' will return real val #=v

finally: # Resurrect prior index, if necessary:
if idx != wasIdx:
self.currindex(wasIdx)
return MbSubDict(self, got) # ===v

-- Or, using a loop variable to cue the conclusion:

notDone = 1
while notDone:
got.append(rec)
rec = self.db.search(metalbase.NEXT, rec)
if rec: # Validate new rec:
for key, val in pairs:
if getattr(rec, key) != val:
# Done once we're past ordered index recs:
notDone = 0
break

else: # Got to very end:
notDone = 0

if idx != wasIdx:
self.currindex(wasIdx)
return MbSubDict(self, got) # ===v

I'm leaning towards the first version, because i like eliminating
things to check on within a loop. However, i'm concerned that
spurious 'return's are expensive, so that it'll cost lots if i wind up
doing many small searches. Can anyone give me the definitive word
here, about the balance point of the costs? And, have a missed a more
suitable approach?

Thanks!

Ken
ken.manheimer@nist.gov, 301 975-3539

--