Caboose Caboose - 2 months ago 6
C# Question

Try-Catch vs If performance in C#

I'm trying to both learn more about the implications of various design choices, and find the most performant solution for preventing errors in my code. Before diving in, allow me to briefly and generally state my question:


Is a try catch block a more efficient solution to handling an out of bounds exception when compared to and if-statement structure?


I understand that raising exceptions is expensive, but is that cost mitigated by removing unnecessary if-statements?

And now, allow me to state my specific issue to give you more useful information.

I'm building a game, and part of that game is a world-grid solution coupled with a pathfinder. Game Units may request nodes from the world-grid, (by sending coordinate information as an ordered pair (x, z)), to then send to the pathfinder or perform on them some other miscellaneous action. Because nodes are being requested with a large amount of frequency, especially by the pathfinder, this seems like a smart place to try to optimize.

Here is my current code for returning a given node based on its x and z values in the array of nodes:

public Node GetTile(int x, int z)
{
if (x < 0)
x = 0;
if (x >= length_X)
x = length_X - 1;

if (z < 0)
z = 0;
if (z >= length_Z)
z = length_Z - 1;
return tiles [x, z];
}


As you can plainly see, I have several if statements in place to avoid out of bounds exceptions when retrieving a node from world-grid's array of nodes(tiles). Is this the most efficient solution? Could I remove the if's and instead place the return in a try catch block like so:

public Node GetTile(int x, int z)
{
try
{
return tiles[x, z];
}
catch (System.IndexOutOfRangeException e)
{
//handle exception here
//do smart programming fix-y stuff
}
}


This solution works, but is there some reason that I'm not aware of that makes it less efficient? My logic for believing it to be a smarter solution is that I'm removing up to four comparisons every single time the method is called. Considering the circumstances under which the program will actually send in values out side of the bounds are rare, this seems like a good trade off. What I don't know though, is how exceptions work behind the scenes. Will checking for an exception be just as expensive as checking the values manually?

UPDATE:

After reading through the replies here I now have a better understanding of the topic in general. I've run some tests on my code accounting for various cases running 10 million iterations.

In line with my general hypothesis, if we assume that there will never be a case where input results in an exception, then the try catch block is indeed faster. However, in the case where approximately 10% the calls to the method raise an exception, the performance is over 5 times slower. I tested various percentages and it seems that the threshold for better performance in my case is near 1%.

As of yet, I'm not sure what percentage of calls will indeed actually raise an exception, but I believe that the number will be much much lower than 1%. Therefore, I can safely, unless further testing shows otherwise, use the try-catch block to ensure my code runs without fatal errors.

Thanks to everyone who contributed.

Answer

Exceptions are made for things that are uncommon to happens, e.g. Connection Issues, xml-File is not in xml-format and so on.

The performance of exceptions is generally bad compared to some simple if-statement, but there are also situations when exception-handling might be even faster than checking data for validity by yourself, especially if you don't know how to do it fast (e.g. checking a file for correct xml-format).

Performance of exceptions depends on how "deep" you are in your Stack. So when you are on layer 24 of your Application (maybe caused by interceptors and normal logic layers) there is a lot of stacktrace that has to be created.

You can not give a general statement about the performance of exceptions, but when you can avoid exceptions you should. They are made for exceptions as their name already tells.

A small example where you can potentially avoid exceptions:

try
{
    LoginUser("Fooooo", "Bar");
}catch(InvalidPasswordException e){
    MessageBox.Show(e.Message);
}  

private static void LoginUser(string pUsername, string pPassword)
{
    if (pUsername != "Foo" || pPassword != "Bar")
       throw new InvalidPasswordException("Invalid username and/or password");

    GrantAccess(pUsername);
}

Instead of throwing the exception you could also just return a boolean:

if (!LoginUser("Fooooo", "Bar"))
{
    MessageBox.Show(e.Message);
}

private static bool LoginUser(string pUsername, string pPassword)
{
    if (pUsername != "Foo" || pPassword != "Bar")
        return false;

    GrantAccess(pUsername);            
    return true;
} 

Performance-Test: 10000 attempts with false credentials:

throwing Exception: 181990454 ticks

returning boolean: 644 ticks

And we are only 1 layer into the application, so there is not much stacktrace to be generated. I guess you can see and especially feel the difference.

Comments