Performance Rules Of Thumb

10 commentsWritten on February 15th, 2009 by
Categories: Performance

A lot of developers deal with performance differently. Some care too much, trying to optimize every single piece of code they write. Some care too little, not thinking about performance at all until it is proven to be a problem. I think both of these approaches suck and usually try to find a healthy balance between them.

Below is a list of rules of thumb that i always try to keep in mind. Keep in mind that these are just rules of thumb... they are not rules that never should be broken, nor are they applicable to each and every situation. In general though, i do believe that if you keep these in mind you can avoid serious performance issues and the need to do heavy architectural refactoring in the long run. So without further ado, these are the performance-related things that i do care about while i'm writing my code:

  • Be careful with anything that goes out of process (web/wcf service calls, database calls, external systems/components, ...). The cost of these calls is often higher than you'd imagine and might not become noticeable until the load on your system increases, or when you start executing these calls in long loops.
  • Fetch your data in a smart manner... Never retrieve data in a loop, but retrieve it outside of the loop in a more coarse-grained manner. Sometimes it makes sense to use some joins to retrieve data, but in other cases you're better off with executing separate queries to avoid retrieving large Cartesian products. If your data layer implements caching in some way, use it in a smart manner
  • Dispose objects that need it as soon as possible... Not doing this could lead to costly dangling resources and/or memory leaks... if this eventually leads to swapping/paging you end up with abysmal performance
  • Don't transfer more data than you need to. Whether you're sending data over a service or you're pushing HTML to a browser, your total bandwidth and/or the client's download speed is usually limited so this could lead to slowdowns that you can often avoid. Note that i don't recommend making everything as compact as possible, but a little bit of common sense can go a long way here.
  • Don't go crazy with multi-threading and asynchronous operations. While these can generally help a lot when it comes to responsiveness (and thus, the perceived 'slowness' of your application) they aren't always the perfect solution. I once saw an 'architect' run a data import process (which had to insert that data in a remote database) over 64 threads, because it was too slow in one thread. He was surprised to see that his 64-thread solution wasn't faster than his single-threaded version. I wasn't surprised at all... I suggested getting rid of the multi-threading and to batch the insert statements, which improved the situation greatly.
  • Don't hold on to large sets of data for too long. A large set of data could be a lot of database records, but it could just as well be a lot of strings, or just other objects in general. Keeping these in memory for a long time prevents them from being garbage collected as soon as they can be, which can greatly increase memory pressure in your system. Be especially careful with long-running loops that iterate over large sets of data. If you no longer need the data after you've left the loop, you're often better off getting rid of each item in the set as you're done processing it.

And that's pretty much it... outside of the stuff listed above, i typically don't care about performance. I try to keep my code clean and focused, and rely on profiling to identify performance hotspots. When the profiler identifies problems, they are often more easy to solve if you've kept your code clean than it would be if you had tried to prematurely optimize in the wrong places.

  • http://skepticabin.wordpress.com/ Eric

    I would elaborate on “Dispose objects that need it as soon as possible”. In short, I see too much “second guessing” of the garbage collector. In general (this applies .NET):

    (1) Do not call obj.Dispose() but allow the GC to do the work for you—it’s a finely tuned beast that alot of thought has gone into. Yes, this even applies to objects that you *know* use unmanaged resources;
    (2) When dealing with objects that you know use unmanaged resources always try to use a “using” statement to delimit the scope of use.

    Of course (1) and (2) assumes that you’ve correctly implemented the Disposable pattern on anything that you write that directly or indirectly uses unmanaged resources. Be smart about this—I had a colleague who insisted that IDisposable be properly implemented on *all* classes that were written—that’s just silly.

  • http://blogs.microsoft.co.il/blogs/sasha Sasha Goldshtein

    @Eric, a using statement calls Dispose on the object at the end of the scope. So you’re contradicting your own advice. And anyway, it’s extremely important to DO call Dispose on objects that use unmanaged resources, exactly because you DO NOT want to rely on finalization to reclaim these resources.

    The GC can reclaim memory without any effort; any other kind of resource that is cleaned up (by Dispose() and/or a finalizer) requires significant effort if you don’t do it explicitly. I have seen (and blogged about) many bugs that were caused by non-deterministic finalization.

  • http://www.twitter.com/freddy_rios Freddy

    @Eric actually, by doing 2 you are implicitly calling dispose. That is just what it does for you (on either normal execution or when an exception occurs).

  • http://skepticabin.wordpress.com/ Eric

    @Sasha and @Freddy – I’m aware of the implicit call on Dispose with “using”. Perhaps I should have phrased things differently: “Use a using statement as opposed to obj.Dispose() to explicitly delimit the lifetime of the associated unmanaged resource(s).”.

    @Sasha – I would say whether or not you explicitly dispose of unmanaged resources is dependent on a number of factors, including whether or not such resources are limited. So, the time at which the resource will be cleaned up is indeterminate? If this doesn’t matter, then I don’t see the problem.

  • http://davybrion.com Davy Brion

    @Eric

    the using statement is great and all, but it’s only usable within the scope of a method… if you need to hold on to an IDisposable for a longer time, you need to make sure that the containing object explicitly calls .Dispose on the IDisposable, and in fact, i would recommend that in this specific scenario, the containing object implements IDisposable as well

  • http://blogs.microsoft.co.il/blogs/sasha Sasha Goldshtein

    @Eric: Time might not seem to matter at first, and start to matter in a production scenario. Your app might be dealing with 50 Bitmap objects at first, but due to popularity and market demands all of the sudden you have to create and destroy thousands of Bitmap objects per minute. All of the sudden, deterministically releasing resources becomes important.

    Precisely BECAUSE it is usually hard to evaluate the factors that affect unmanaged resource consumption, the rule of thumb should be to explicitly dispose such resources.

  • Pingback: Software Quality Digest - 2009-02-18 | No bug left behind

  • Pingback: Weekly Web Nuggets #52 : Code Monkey Labs

  • http://PracticeThis.com Alik Levin | PracticeThis.com

    Gold,
    it must be on top of every developer’s and architect’s mind.
    Good stuff, liked it

  • http://www.tensailabs.com/ Gregory Kornblum

    A very solid set of guidelines. Very good stuff. Trust me, I have felt the pain of not following some of them.