473,699 Members | 2,501 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Magic Optimisation

Hello People.

I've have a very tight inner loop (in a game app, so every millisecond
counts) which I have optimised below:

def loop(self):
self_pool = self.pool
self_call_exit_ funcs = self.call_exit_ funcs
self_pool_pople ft = self.pool.pople ft
self_pool_appen d = self.pool.appen d
check = self.pool.__len __
while check() > 0:
task = self_pool_pople ft()
try:
task.next()
except StopIteration:
self_call_exit_ funcs(task)
return
self_pool_appen d(task)

This style of optimisation has shaved _seconds_ from my iteration
cycle, esp. when I have many registered tasks, so this style of
optimisation is very important to me.

However, it is very ugly. Does anyone have any tips on how I could get
this optimisation to occor magically, via a decorator perhaps?

Sw.

Sep 5 '05
16 1487
On 5 Sep 2005 07:27:41 -0700, "Paul McGuire" <pt***@austin.r r.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_pople ft = self.pool.pople ft
self_pool_appen d = self.pool.appen d
self_call_exit_ funcs = self.call_exit_ funcs
check = self.pool.__len __
while check() > 0:
try:
while check() > 0:
task = self_pool_pople ft()
task.next()
self_pool_appen d(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&event s: 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_pople ft = self.pool.pople ft
self_pool_appen d = self.pool.appen d
self_call_exit_ funcs = self.call_exit_ funcs
try:
while True:
task = self_pool_pople ft()
if task.next() is None:
self_call_exit_ funcs(task)
else:
self_pool_appen d(task)
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_rotat e() 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_rotat e = self.pool.rotat e
try:
while True:
if self.pool[-1]() is None:
self_call_exit_ funcs(self_pool _pop())
else:
self_pool_rotat e()
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.

Regards,
Bengt Richter
Sep 5 '05 #11
On Mon, 05 Sep 2005 21:39:31 GMT, bo**@oz.net (Bengt Richter) wrote:
On 5 Sep 2005 07:27:41 -0700, "Paul McGuire" <pt***@austin.r r.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_pople ft = self.pool.pople ft
self_pool_appen d = self.pool.appen d
self_call_exit_ funcs = self.call_exit_ funcs
check = self.pool.__len __
while check() > 0:
try:
while check() > 0:
task = self_pool_pople ft()
task.next()
self_pool_appen d(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&event s: 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_pople ft = self.pool.pople ft
self_pool_appen d = self.pool.appen d
self_call_exit_ funcs = self.call_exit_ funcs
try:
while True:
task = self_pool_pople ft()
if task.next() is None:
self_call_exit_ funcs(task)

^^^^^^^^^^^^^^^ ^^^^^^^ oops, need to switch if and else branches else:
self_pool_appen d(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_rotat e() 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_rotat e = self.pool.rotat e
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_rotat e() ^^^^^^^^^^^^^^^ ^^^^^^^ 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
Sep 6 '05 #12

Paul McGuire 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.


Your suggested optimisation worked nicely. It shaved 0.02 seconds from
a loop over 10000 iterators, and about 0.002 seconds from a loop over
1000 iterators.

Sep 6 '05 #13
ABO
Bengt Richter wrote:
On 5 Sep 2005 07:27:41 -0700, "Paul McGuire" <pt***@austin.r r.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
[...] 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

[...]

The rule of thumb with exceptions is use them for infrequent events. If
you keep to this you end up with clean and fast code.

Provided task.next() raises StopIteration less than about 25% of the
time it is called, it is cleaner and more efficient to use an exception
than to return None. It is also more efficient to handle terminating by
allowing popleft trigger an exception. Try the following;

def loop(self):
self_call_exit_ funcs = self.call_exit_ funcs
self_pool_pople ft = self.pool.pople ft
self_pool_appen d = self.pool.appen d
while True:
try:
task = self_pool_pople ft()
task.next()
self_pool_appen d(task)
except StopIteration:
self_call_exit_ funcs(task)
except IndexError:
break

There are other "optimisati ons" that could be applied that make this
code faster but uglier. For example, putting another "while True: loop
inside the try block to avoid the try block setup each iteration. Also,
exception handling is slower when you specify the exception class (it
has to check if the exception matches), so you might be able to arrange
this with an anonymous accept: block around the task.next() to handle
the StopIteration exception.

Another thing that disturbs me is the popfirst/append every iteration.
Depending on how many loops through all the tasks before one
"finishes", you might find it more efficient to do this;

def loop(self):
self_pool = self.pool
self_pool_remov e = self_pool.remov e
self_call_exit_ funcs = self.call_exit_ funcs
while self_pool:
try:
for task in self_pool:
task.next()
except:
self_pool_remov e(task)
self_call_exit_ funcs(task)

Sep 14 '05 #14

"ABO" <ab*@google.com > wrote in message
news:11******** **************@ g47g2000cwa.goo glegroups.com.. .
There are other "optimisati ons" that could be applied that make this
code faster but uglier. For example, putting another "while True: loop
inside the try block to avoid the try block setup each iteration.


In CPython, 'setting up' try-blocks is (intentionally) very fast, perhaps
as fast or faster than one interation loop.

tjr

Sep 14 '05 #15
Terry -

If setting up a try-block is as fast (or "takes as long") as one
iteration loop, then wont putting a try-block inside a loop double the
execution time?

-- Paul

Sep 14 '05 #16

"Paul McGuire" <pt***@austin.r r.com> wrote in message
news:11******** *************@g 43g2000cwa.goog legroups.com...
Terry -

If setting up a try-block is as fast (or "takes as long") as one
iteration loop, then wont putting a try-block inside a loop double the
execution time?


It will double (more or less) the loop overhead. The effect of that
depends on the overhead/payload ratio. And, I was responding to the idea
that adding a loop to avoid most try statements would be significantly
faster.

Terry J. Reedy

Sep 14 '05 #17

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
1877
by: Simon Elliott | last post by:
What optimisation do compilers typically provide when passing STL containers around? For example, if I do something like this: struct Tbloggs { std::string s1; }; typedef std::vector<Tbloggs> TbloggsList;
17
2365
by: EC-AKD | last post by:
Hi All, I am new to the concept of optimising codes in C. I was wondering if C level inlining of code is any way comparable to macros. I believe that inlining is equivalent to writing macros. However I had this strange feeling if I should go for macros wherever necessary instead of inlining the codes. In my project, I have to use basic operations like add and sub many times. So I initially inlined them and found a lot of optimisation.
8
1894
by: Jon Maz | last post by:
Hi, I'm facing a code-optimisation issue on an asp.net/vb.net/SQL Server 2000 project. A web page containing not much more than 3 DropDownLists is taking nigh on 6 seconds to load, because each ddl opens up a separate connection to the DB, pulls out its data, and closes its own connection before the next ddl repeats the process. The code to handle each DDL's connection to the DB is packaged in an object (presentation-layer code...
1
1997
by: David Welch | last post by:
Hi, I have a bit of code where I am relying on empty base member optimisation. The bit of code is below: template<typename Enum> struct EncodePrefix { template<Enum e> struct Apply
1
2058
by: grid | last post by:
Hi, I was exploring the affect of cache on program performance/optimisation.Is it the compilers responsibility only to consider this kind of optimisation or the programmer can do his bit in this case ? Reading through the "Expert C Programming" text,it mentions how the below program can be efficient taking the cache details into accont. The below program can be executed using the two versions of copy alternatively and running the time...
16
2598
by: per9000 | last post by:
Hi, I recently started working a lot more in python than I have done in the past. And I discovered something that totally removed the pretty pink clouds of beautifulness that had surrounded my previous python experiences: magic names (I felt almost as sad as when I discovered the strange pink worms that eat you in nethack, not to mention the mind flayers - I really hate them). I guess all programming languages have magic names to some...
2
2578
by: jyck91 | last post by:
i have done the magic square: #include <stdio.h> #include <stdlib.h> #include <string.h> #define SIZE 13 main() { FILE *fp; int i, j, n, row, column;
2
1251
by: special_dragonfly | last post by:
Hello, I know this might be a little cheeky, and if it is, please say, but I need a little hand optimising some code. For the simple reason that this is 'company' code and I have no idea what I'm allowed to release and not as the case may be I've changed anything that could give an indication of the company - if that makes any sense... for the code below: text_buffer is a single record from an XML stream. I can't read in the entire XML...
9
16150
by: Larry Hale | last post by:
I've heard tell of a Python binding for libmagic (file(1) *nixy command; see http://darwinsys.com/file/). Generally, has anybody built this and worked with it under Windows? The only thing I've been able to find is the python-magic module at http://hupp.org/adam/hg/python-magic/. Is this "THE" python-magic module. (It seems to be to me, but obviously I don't know. :)
0
8612
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
1
8905
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8880
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
7743
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
5869
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4373
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4625
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
2342
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2008
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.