The Invent with Python Blog

Fri 19 August 2011

Nobody Cares About a Few Million Nanoseconds

Posted by Al Sweigart in misc   

A Clever Programming Trick...

If you need to swap the values of two variables, this usually requires a third temporary variable (that is, if you're not using a language like Python that supports the a, b = b, a syntax.) It looks something like this:

temp = a;
a = b;
b = temp;

But if these are integer variables, there's a nifty trick to save yourself a little bit of memory. You can use arithmetic instead of a temporary variable:

a = a + b;
b = a - b;
a = a - b;

If the integers on your platform are 32-bits, your new swap will save four bytes of memory.


This is a mistake a lot of new programmers make. The coder comes up with some clever trick or that can save a few bytes of memory or shave a few nanoseconds off of a function. You must learn that these "clever tricks" aren't really worth it. These clever tricks are called "micro-optimizations", and back when computers only had 64KB of memory, they made sense. More often than not these days they just make the code less readable and harder to debug. Memory is cheap, and humans won't notice a few more milliseconds of waiting time (unless the delay is for a frequent and visible event.)

Think about it. In the time that it takes for you to read this sentence, several billion nanoseconds have already passed. Billions. A clever trick that saves a few nanoseconds at the expense of code readability is not going to be noticed. NOBODY CARES ABOUT A FEW MILLION NANOSECONDS.

"Premature optimization is the root of all evil."

This notion is encapsulated in Don Knuth's venerated saying, "Premature optimization is the root of all evil." In other words, you should concentrate on making your software, then concentrate on making it work correctly, and then later (if you have to) concentrate on making it fast. Trying to optimize the code before then is a fool's errand. Most likely, the software you write today will have been replaced or tossed out or forgotten three years from now. (Unless you are writing Oregon Trail, in which case old people will keep writing emulators to play it out of some silly sense of nostalgia.)

Some examples of clever tricks you should never do:

  • The integer variable swap trick shown above.
  • Reusing variables for different purposes. Separate variable names for separate values makes debugging easier.
  • Using a float instead of a double. (You save a little memory but the smaller precision can result in notoriously tricky rounding errors.)
  • Doing math in the code for the computer, such as multiplying a value by 525600 (the number of minutes in a year) instead of multiplying a value by 60 * 24 * 365 (which is more obvious). The compiler/interpreter will most likely optimize these automatically anyway.
  • Combining functions together into fewer functions to reduce the overhead of function calls.
  • "Loop unrolling/unwinding", that is, copying/pasting code that would normally be in a loop so that you do not have the overhead of looping for each iteration. (Don't even think about using Duff's device.)
  • Short variable and function names. This doesn't even make the compiled program run better, it just makes the source code slightly smaller. That the variable "mttl" means "monthly total" will be completely impossible to know, even for the programmer who wrote it, once a few weeks have elapsed. Single-letter variable names, unless it's something like x and y for coordinates or i and j for a loop's variable, should never be used. Don't use the variable name "n" to store a number: have the variable name describe what the number is used for.

Don't Guess, Use a Profiler

When you do begin the process of optimizing your program, don't just look through your code and guess where the slow and bloated parts are. Run your code under a profiler, which will scientifically tell you how much memory and how long is spent executing each function in your program. (For Python, the cProfile module does a good job. See the Instant User's Manual to learn how to profile your Python code.)

Unless the software is being run on a computer that is going into space, a nuclear reactor, or someone's chest cavity, these micro-optimizations don't matter 97% of the time. Even when programming for smart phones (which have limited system resources) you need to focus on improvements that result in orders of magnitude improvements, not micro-optimizations. These usually involve caching data or using entirely different algorithms, not tiny clever tricks that make the code inscrutable.

Code that is straightforward to read is easy to understand. Code that is easy to understand is less likely to have bugs. Code that is easy to understand is easy to extend with new features. And it's bug-free programs with cool features that people want. Nobody cares about a few million nanoseconds.

More info about this topic here:

Also, to head off criticisms of this article, there are times when micro-optimizations are needed. That's why Knuth says they're unneeded only 97% of time.