We've seen plenty of questions about when and why to use try
/catch
and try
/catch
/finally
. And I know there's definitely a use case for try
/finally
(especially since it is the way the using
statement is implemented).
We've also seen questions about the overhead of try/catch and exceptions.
The question I linked to, however, doesn't talk about the overhead of having JUST try-finally.
Assuming there are no exceptions from anything that happens in the try
block, what's the overhead of making sure that the finally
statements get executed on leaving the try
block (sometimes by returning from the function)?
Again, I'm asking ONLY about try
/finally
, no catch
, no throwing of exceptions.
Thanks!
EDIT: Okay, I'm going to try to show my use case a little better.
Which should I use, DoWithTryFinally
or DoWithoutTryFinally
?
public bool DoWithTryFinally()
{
this.IsBusy = true;
try
{
if (DoLongCheckThatWillNotThrowException())
{
this.DebugLogSuccess();
return true;
}
else
{
this.ErrorLogFailure();
return false;
}
}
finally
{
this.IsBusy = false;
}
}
public bool DoWithoutTryFinally()
{
this.IsBusy = true;
if (DoLongCheckThatWillNotThrowException())
{
this.DebugLogSuccess();
this.IsBusy = false;
return true;
}
else
{
this.ErrorLogFailure();
this.IsBusy = false;
return false;
}
}
This case is overly simplistic because there are only two return points, but imagine if there were four... or ten... or a hundred.
At some point I would want to use try
/finally
for the following reasons:
- Keep to DRY principles (especially as the number of exit points gets higher)
- If it turns out that I'm wrong about my inner function not throwing an exception, then I want to make sure
this.Working
is set tofalse
.
So hypothetically, given performance concerns, maintainability, and DRY principles, for what number of exit points (especially if I can assume that all inner exceptions are caught) do I want to incur whatever performance penalty is associated with try
/finally
?
EDIT #2: I changed the name of this.Working
to this.IsBusy
. Sorry, forgot to mention this is multithreaded (though only one thread will ever actually call the method); other threads will be polling to see if the object is doing its work. The return value is merely success or failure for if the work went as expected.
Why not look at what you actually get?
Here is a simple chunk of code in C#:
And here is the resulting IL in the debug build:
and here's the assembly generated by the JIT when running in debug:
Now, if I comment out the try and finally and the return, I get nearly identical assembly from the JIT. The differences you'll see are a jump into the finally block and some code to figure out where to go after the finally is executed. So you're talking about TINY differences. In release, the jump into the finally will get optimized out - braces are nop instructions, so this would become a jump to the next instruction, which is also a nop - that's an easy peephole optimization. The pop eax and then jmp eax is similarly cheap.
So you're talking very, very tiny costs for try/finally. There are very few problem domains where this matters. If you're doing something like memcpy and put a try/finally around each byte being copied and then proceed to copy hundreds of MB of data, I could see that being an issue, but in most usage? Negligible.
try/finally
is very lightweight. Actually, so istry/catch/finally
as long as no exception is thrown.I had a quick profile app I did a while ago to test it out; in a tight loop, it really added nothing at all to execution time.
I'd post it again, but it was really simple; just run a tight loop doing something, with a
try/catch/finally
that does not throw any exceptions inside the loop, and time the results against a version without thetry/catch/finally
.Let's actually put some benchmark numbers to this. What this benchmark shows is that, indeed, the time of having a try/finally is about as small as the overhead of a call to an empty function (probably better put: "a jump to the next instruction" as the IL expert stated it above).
Result: 33,33,32,35,32 63,64,69,66,66 (milliseconds, make sure you have code optimization on)
So about 33 milliseconds overhead for the try/finally in 10 million loops.
Per try/finally then, we are talking 0.033/10000000 =
3.3 nanoseconds or 3.3 billionth of a second overhead of a try/finally.
What Andrew Barber said. The actual TRY/CATCH statements add no/negligible overhead unless an exception is thrown. There's nothing really special about finally. Your code just always jumps to finally after the code in the try+catch statements are done
In lower levels
finally
is just as expensive as anelse
if the condition not met. It is actually a jump in assembler (IL).So let's assume there's an overhead. Are you going to stop using
finally
then? Hopefully not.IMO performance metrics are only relevant if you can choose between different options. I cannot see how you can get the semantic of
finally
without usingfinally
.