Gday all,
When I was playing around with topographic map generation ( https://forum.unity3d.com/threads/wip-small-works-game-programming-thread.146445/page-27#post-2872694 ) I ended up using quite large 2D arrays (1000 x 1000 and greater).
As part of the vegetation generation, a basic heatmap of each tree is developed; each tree affects cells a few each side of it. The result of this required iteration a few indexes to the left/right of the array many times. In order to deal with array index out of bounds issues, I used a try catch instead of an if statement (not just out of laziness!)
Obviously the accepted way to do this is using an if statement each iteration to ensure that the index you are about to check is not outside the bounds.
My thoughts were that with 1000000 cells, the liklihood of a cell being outside the array index is quite low so the additional exception handling overhead wouldnt need to be called very often as opposed to the (still quite fast) if statement check every iteration.
All the research I have done indicates that the try catch used in this fashion is extremely poor form and wouldn’t net any notable benefits however based on my results, these statements may be referring to (much) smaller iteration sizes.
Tests
I ran a few tests using the profiler and came up with some interesting results.
Test setup
public int size;
public int[,] arrayTest;
int temp;
void Awake () {
arrayTest = new int[size, size];
}
void Start()
{
StartCoroutine(DoTest());
}
IEnumerator DoTest()
{
yield return new WaitForSeconds(1);
CheckTry();
yield return new WaitForSeconds(2);
CheckIf();
yield return new WaitForSeconds(1);
Debug.Break();
}
(The temp variable is just to do some ‘work’ inside the loops as per below)
Test 1 : one index either side
void CheckTry()
{
for (int x = 0; x < arrayTest.GetLength(1); x++)
{
for (int y = 0; y < arrayTest.GetLength(0); y++)
{
try
{
temp = arrayTest[x - 1, y];
}
catch (System.Exception e) { }
try
{
temp = arrayTest[x + 1, y];
}
catch (System.Exception e) { }
try
{
temp = arrayTest[x, y-1];
}
catch (System.Exception e) { }
try
{
temp = arrayTest[x, y+1];
}
catch (System.Exception e) { }
}
}
}
void CheckIf()
{
for (int x = 0; x < arrayTest.GetLength(1); x++)
{
for (int y = 0; y < arrayTest.GetLength(0); y++)
{
if (x > 0)
{
temp = arrayTest[x - 1, y];
}
if (y > 0)
{
temp = arrayTest[x, y - 1];
}
if (x < arrayTest.GetLength(1)-1)
{
temp = arrayTest[x + 1, y];
}
if (y < arrayTest.GetLength(0)-1)
{
temp = arrayTest[x, y + 1];
}
}
}
Test 2 : Multiple indexes either side (closer to how I was developing the heat maps)
void CheckTry()
{
for (int x = 0; x < arrayTest.GetLength(1); x++)
{
for (int y = 0; y < arrayTest.GetLength(0); y++)
{
for (int xOffset = -3; xOffset < 4; xOffset++)
{
for (int yOffset = -3; yOffset < 4; yOffset++)
{
try
{
temp = arrayTest[x + xOffset, y + yOffset];
}
catch (System.Exception e) { }
}
}
}
}
}
void CheckIf()
{
for (int x = 0; x < arrayTest.GetLength(1); x++)
{
for (int y = 0; y < arrayTest.GetLength(0); y++)
{
for (int xOffset = -3; xOffset < 4; xOffset++)
{
for (int yOffset = -3; yOffset < 4; yOffset++)
{
if (x + xOffset >= 0 && x + xOffset < arrayTest.GetLength(1) && y + yOffset >= 0 && y + yOffset < arrayTest.GetLength(0))
{
temp = arrayTest[x + xOffset, y + yOffset];
}
}
}
}
}
}
Results
size (of each array dimension)
try → ms for the try catch implementation
if → ms for the if{} implementation
Test 1:
100
try → 1.73
if → 0.94
500
try → 15.87
if → 18.50
1000
try → 50.61
if → 73.77
5000
try → 1063.62
if → 1818.01
10000
try → 4103.19
if → 7226.37
Test 2
100
try → 41.46
if → 23.17
500
try → 303.68
if → 579.31
1000
try → 867.79
if → 2325.95
5000
try → 14197.22
if → 59067.40
This seems to show it is much better to use the try catch for performance reasons when there is a very large range of iterations with a low chance of an error (despite the conventions I have always been taught)
Interested to hear thoughts/insight from more experienced coders, in particular any additional considerations that may offset the performance increase.
Cheers.