Magic Optimisation

Bengt Richter bokr at
Mon Sep 5 23:39:31 CEST 2005

On 5 Sep 2005 07:27:41 -0700, "Paul McGuire" <ptmcg at> wrote:

>I still think there are savings to be had by looping inside the
>try-except block, which avoids many setup/teardown exception handling
>steps.  This is not so pretty in another way (repeated while on
>check()), but I would be interested in your timings w.r.t. your current
>    def loop(self):
>        self_pool_popleft = self.pool.popleft
>        self_pool_append = self.pool.append
>        self_call_exit_funcs = self.call_exit_funcs
>        check = self.pool.__len__
>        while check() > 0:
>            try:
>                while check() > 0:
>                    task = self_pool_popleft()
>                    self_pool_append(task)
>            except StopIteration:
>                self_call_exit_funcs(task) 

Why not let popleft trigger an exception out of while True instead,
and prevent tasks from raising StopIteration, and let them yield a None
to indicate keep scheduling with no special action, and something else
for optional differentiation of various exit options, e.g., zero for die,
and nonzero for suspension waiting for event(s) E.g., a returned integer
could be an event mask or single index (+ vs -) for thing(s) to wait for.
If you work things right, event check in the loop can be an if like
if waitedfor&events: process_events(),  which most of the time is a fast no-op).

Then (without event stuff, and untested ;-) maybe something like:

     def loop(self):
         self_pool_popleft = self.pool.popleft
         self_pool_append = self.pool.append
         self_call_exit_funcs = self.call_exit_funcs
             while True:
                 task = self_pool_popleft()
                 if is None:
         except Indexerror:

You could even consider putting the bound methods in
the deque instead of the task, and using deque rotation instead
of popping and appending. Then, if you put the's in
reverse order in the deque to start with, self_pool[-1] will be
the first, and self_pool_rotate() will bring the next into position.
Which would make it look like (untested!):

     def loop(self):
         self_pool_pop = self.pool.pop
         self_call_exit_funcs = self.call_exit_funcs
         self_pool_rotate = self.pool.rotate
             while True:
                 if self.pool[-1]() is None:
         except Indexerror:

IWT if the pool remains unchanged most of the time, pool_rotate() ought
to be faster than popping and appending. Note that exit_funcs will need
a mapping of -> task most likely, unless communication is
entirely via a mutable task state object, and all that's needed is to
me map to that and mess with exit state there and trigger a final .next()
to wrap up the generator.

Bengt Richter

More information about the Python-list mailing list