Error Handling
Error handling is a fact of life for applications, but that doesn't mean it should slow you down. Here are a few tips for avoiding potential error-handling-
related
performance issues.
On Error Goto
and
On Error Resume
Next
vs. Exceptions
The
On Error
statement should be familiar to Visual Basic developers. After all, it was the only error-handling mechanism built into previous versions of Visual Basic. Visual Basic .NET does provide these error-handling constructs, but they're for backward compatibility only. Structured exception handling is now the order of the day. Even though it's not
necessarily
obvious, just adding
On Error
to a method will result in your code running more slowly, regardless of whether errors are actually occurring. To see why this is true, let's compare two
methods
:
PrivateSubTryCatch_Simple()
Try
Console.Write("This ")
Console.Write("is ")
Console.Write("a ")
Console.Write("good ")
Console.WriteLine("test.")
CatchexAsException
Console.WriteLine("Thecommandfailed")
EndTry
EndSub
PrivateSubOnError_Simple()
OnErrorResumeNext
Console.Write("This ")
Console.Write("is ")
Console.Write("a ")
Console.Write("bad ")
Console.WriteLine("test.")
EndSub
Someone comparing the two methods might think that the
OnError_Simple
method is more efficient merely because it appears to contain less code. This couldn't be further from the truth. The compiled code can be quite different. I'll leave the exercise of checking out the actual MSIL output to you, but I've grabbed some information that
demonstrates
, in part, what the problem is:
.methodprivatestaticvoidTryCatch_Simple()cilmanaged
{
//Codesize77(0x4d)
...
}//endofmethodModule1::TryCatch_Simple
.methodprivatestaticvoidOnError_Simple()cilmanaged
{
//Codesize180(0xb4)
...
}//endofmethodModule1::OnError_Simple
What should you make of these two MSIL examples? First, notice how much longer
OnError_Simple
is. At the top of each example, you'll see a comment that describes the code size of each method. The
OnError_Simple
method weighs in at 180 bytes, while the
TryCatch_Simple
method weighs in at 77 bytes (less than half). But of course, this doesn't tell the whole story. Remember, I said that less code does not always run faster, but here it definitely does. To help
illustrate
this, I created a sample application called OnErrorPerformance (one of this chapter's samples files) using both the
TryCatch_Simple
and
OnError_Simple
methods described above and two similar, but larger, methods (
essentially
duplicating the internal code several times). The
numbers
are interesting:
TestNameTryCatchOnErrorDiff
-----------------------------------------------
SimpleTest1602192250342564.0%
SimpleTest1602192230315169.6%
SimpleTest1602192240328866.7%
SimpleTest1502055240328862.5%
LongerTest32043841261726225.4%
LongerTest32043841271739925.2%
LongerTest33045211241698826.6%
LongerTest32043841251712525.6%
You can see that using
On Error
is about 25 percent slower than using
Try Catch
for the "Simple Test". Not too bad, right? Well, as you can see, it gets worse. In fact, it gets much worse. The larger the method, the
worse
the effect on performance. The larger method tests
demonstrate
that admirably. The
OnError_Longer
method is almost four times slower than the
TryCatch_Longer
method. Wow.
Using the old Visual Basic style of error handling is terrible for performance. Incidentally, this was also true in Visual Basic 6.0. Essentially,
On Error
injects a lot of code into a method to perform its magic. This results in your method containing a placeholder for each physical line of code, similar to using a line label. The method is then
enclosed
in one
Try...Catch
, and when an exception occurs, the line to go to is determined by a switch clause and the last saved location. As you might expect, this results in a large amount of overhead for such a little statement. The reality is that this is one of the most inefficient forms of error handling you can use. (Of course, some industrious individual might
prove
us wrong ”someone can always come up with a more inefficient solution.)
Burn this into your brain before you go on to the next section: exception handling good.
On Error
bad. Really bad.
Exception Handling Best Practices
I talked a lot about proper exception handling in Chapter 2, and I don't want to belabor the subject here. I will, however say this: exceptions should be exceptional. Exception handling is
fairly
expensive. Granted, when no exceptions are being thrown, there is little impact on performance. But if you throw exceptions regularly in your code, you'll likely experience significant performance degradation. Two rules should apply to exception handling:
OK, everyone clear? Good. Let's move on.
|