Magic Optimisation

Bengt Richter bokr at oz.net
Tue Sep 6 03:38:44 CEST 2005


On Mon, 05 Sep 2005 21:39:31 GMT, bokr at oz.net (Bengt Richter) wrote:

>On 5 Sep 2005 07:27:41 -0700, "Paul McGuire" <ptmcg at austin.rr.com> 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
>>code.
>>
>>    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()
>>                    task.next()
>>                    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
>         try:
>             while True:
>                 task = self_pool_popleft()
>                 if task.next() is None:
>                     self_call_exit_funcs(task) 
                      ^^^^^^^^^^^^^^^^^^^^^^ oops, need to switch if and else branches
>                 else:    
>                     self_pool_append(task)
                      ^^^^^^^^^^^^^^^^^^^^^^ oops, need to switch if and else branches
>         except Indexerror:
>             pass
>
>You could even consider putting the bound task.next methods in
>the deque instead of the task, and using deque rotation instead
>of popping and appending. Then, if you put the task.next'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
>         try:
>             while True:
>                 if self.pool[-1]() is None:
>                     self_call_exit_funcs(self_pool_pop())
                      ^^^^^^^^^^^^^^^^^^^^^^ oops, need to switch if and else branches
>                 else:    
>                     self_pool_rotate()
                      ^^^^^^^^^^^^^^^^^^^^^^ oops, need to switch if and else branches
>         except Indexerror:
>             pass
>
>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.next -> 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.
>
Sorry. I wonder what else I goofed up ;-)

Regards,
Bengt Richter



More information about the Python-list mailing list