次の方法で共有


Exceptions are expensive!

Hey! Don't we all use Exceptions in managed code to indicate the caller that something is wrong? That's a really bad habit! - "Hey maaaan, it's the 21st century, passing back HRESULTs is over!" - not yet, you'll see it: did you know that if your caller can systematically force your code to throw an exception (by passing wrong parameters, etc), your application could be DOSed down? It's just a matter of the amount of threads running on the defender's box and the power of the server your code running at. To demonstrate this thingy, I hammered together a small app:

The following is a function that can work in two different ways:

  1. Returning an exception, simulating a function that communicates back to its caller by throwing exceptions on deterministic inputs. MyOwnException is just a class inherited from the ApplicationException class
  2. Returning an integer number, simulating a function that works in an "old-fashioned" HRESULT-way 
 static int TesterMethod(bool throwException)
{
    if (throwException)
    {
        throw new MyOwnException();
    }
    else
    {
        return 1;
    }
}

(HRESULT is representing an alternative way of passing back the result of a function as a variable or pointer, it's not neccessarily should be the old-fashioned HRESULT, it could be a structure or class containing information about what happened)

... and here's the function that will drive this baby: it's simple: there's a stopwatch we use to measure time, and we call the function in both ways 1,000 times:

 static void Main(string[] args)
{
    Stopwatch stopWatch = Stopwatch.StartNew();
    
    // PHASE I: DOING THE EXCEPTION-TEST
    
    // Reset and start the stopwatch
    stopWatch.Reset();
    stopWatch.Start();
    
    // Call the function 1,000 times, an exception will be
    //  thrown at every call
    for (int i = 0; i < 1000; i++)
    {
        try
        {
            TesterMethod(true);
        }
        catch (MyOwnException)
        {
            // Do something to handle ...
        }
    }
    
    // Stop the watch and show the time elapsed
    stopWatch.Stop();
    Console.WriteLine("Exception: " + stopWatch.Elapsed);

    
    // PHASE II: DOING THE "HRESULT" TEST

    // Reset and start the stopwatch again
    stopWatch.Reset();
    stopWatch.Start();
    
    // Calling the function 1,000 times again, but now in
    //  the HRESULT-way
    int retVal = 0;
    for (int i = 0; i < 1000; i++)
    {
        retVal = TesterMethod(false);
    }
    
    // Stop the stopwatch and display the results
    stopWatch.Stop();
    Console.WriteLine("HRESULT " + stopWatch.Elapsed);

}

Surprise!

 Exception: 00:00:03.1247094<br>HRESULT:   00:00:00.0000287

I hope that you noticed the seconds part, not only the milliseconds part! After some time, I was rethinking the whole thing, because it seemed to be too much of a difference, then I found that I made a mistake when measuring the performance: I was running the code from the Visual Studio IDE, meaning that I was debugging the process, which slows down 1st chance exceptions, so a big part of this difference was due to the operating system informing the debugger about the 1st chance exceptions. Release compiled the project, ran it outside the debugger and got a much better performance for exceptions, but still a huge difference:

 Exception: 00:00:00.2039267<br>HRESULT:   00:00:00.0000058

This is all about performance and security. One can say that these are just milliseconds per one thousand cycles. That's true for one thread, but think about an ASP.net application or a service accepting huge amount of TCP connections, with 25 worker threads per processor. If there's a function inside that can be forced from outside to throw an exception, this could be a big performance impact on your service. So, think twice before throwing an exception.

Comments

  • Anonymous
    November 08, 2006
    Exactly what does that HRESULT mean? What is the call stack? There is a lot of useful information that can be included in exceptions. An HRESULT does not tell me anything useful. If I am lucky, I may be able to look it up. Regardless of the numbers, exceptions when properly used are the best way to go. An exception should occur in exceptional circumstances. If they are occurring over and over multiple times, then there is a problem with the code and it needs to be fixed.

  • Anonymous
    November 08, 2006
    Yes, that's right! The 2 problems are (1) the way programmers use Exceptions sometimes, and (2) the way Windows handles exceptions that makes the whole process very slow

  • Anonymous
    November 08, 2006
    The comment has been removed

  • Anonymous
    November 08, 2006
    So something exceptional happened 1000 times and it only cost you 3 seconds? Seems VERY acceptable to me.

  • Anonymous
    November 08, 2006
    Jack Bond: it's not neccessarily an exceptional thing all the time, especially when it can be reproduced just by passing a wrong parameter. Compare its cost with the other case!

  • Anonymous
    November 08, 2006
    As with all things, exceptions can be misused. While such code does exist, it is very poor. A peer review of the code may identify the issue. If not, a profiler would be able to. I could scatter my code with many large loops that do absolutely nothing. Or I could allocate massively large arrays and never use them. However, that does not mean that loops or arrays are bad things. They are just not being used properly. As pointed out, an exception should be used for exceptional cases. Well written code should validate passed arguments. By catching the exception, you are declaring that you can handle it. If you are going to throw an exception and catch it and do absolutely nothing about it, then do not throw it in the first place. Finally, catching System.Exception is fairly poor style.

  • Anonymous
    November 09, 2006
    Hi all - A security question for you all that I haven't had time to think about in depth yet but wanted

  • Anonymous
    April 09, 2008
    So something exceptional happened 1000 times and it only cost you 3 seconds? Seems VERY acceptable to me.

  • Anonymous
    April 09, 2008
    you are right for a desktop application - but imagine it on www.hotmail.com - for every visitor. For the processors', this will be Visitor times 3 seconds :) David