.NET Array Dictionary List String 2D Async DataTable Dates DateTime Enum File For Foreach Format IEnumerable If IndexOf Lambda LINQ Parse Path Process Property Regex Replace Sort Split Static StringBuilder Substring Switch Tuple


C#:Switch

If vs. switch. The performance of if and switch is rarely critical. But to increase your understanding of the execution engine, knowing some of the performance details is useful. We compare the performance of if-statements and switch-statements.

Warning: These benchmarks are of limited practical use. They are mainly useful when you are trying to determine when to choose switch.


Example. To start, this program declares two methods that are tested. One is called IsValidIf—it implements a selection with several if-statements. The second is called IsValidSwitch—it implements a selection as a switch.

Note: The results of the two methods on all inputs are equivalent—they have the same effects.

And: When this program is executed, the time required per call of each of those methods is reported.

C# program that tests if and switch performance

using System;
using System.Diagnostics;

class Program
{
    static bool IsValidIf(int i)
    {
	// Uses if-expressions to implement selection statement.
	if (i == 0 ||
	    i == 1)
	{
	    return true;
	}
	if (i == 2 ||
	    i == 3)
	{
	    return false;
	}
	if (i == 4 ||
	    i == 5)
	{
	    return true;
	}
	return false;
    }

    static bool IsValidSwitch(int i)
    {
	// Implements a selection statement with a switch.
	switch (i)
	{
	    case 0:
	    case 1:
		return true;
	    case 2:
	    case 3:
		return false;
	    case 4:
	    case 5:
		return true;
	    default:
		return false;
	}
    }

    const int _max = 100000000;
    static void Main()
    {
	bool b;
	var s1 = Stopwatch.StartNew();
	for (int i = 0; i < _max; i++)
	{
	    b = IsValidIf(i);
	}
	s1.Stop();
	var s2 = Stopwatch.StartNew();
	for (int i = 0; i < _max; i++)
	{
	    b = IsValidSwitch(i);
	}
	s2.Stop();
	Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000 * 1000) /
	    _max).ToString("0.00 ns"));
	Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000 * 1000) /
	    _max).ToString("0.00 ns"));
	Console.Read();
    }
}

Result: switch faster

3.83 ns [if]
2.88 ns [switch]

The if-statement method required an additional 1 nanosecond per method invocation. The switch implementation was faster. If you look at the intermediate code here, you will see that the switch uses a jump table opcode.

And: The if-statement is implemented with conditional branches. The jump table is faster—it requires fewer steps for certain inputs.

It is tempting to think that a switch is always faster than an equivalent if-statement. However, this is not true. A situation where the switch is slower is when the actual runtime of the program has a very skewed distribution of inputs.

Benchmark

So: If the input is almost always a specific value, then using an if-statement to test for that value may be faster.


Example 2. To continue, we look at a benchmark harness that tests two implementations. Method1 uses, internally, a switch statement. And Method2 uses an if-else if construct. The two methods have the same results.

Note: The methods receive the value zero 60% of the time. They receive the value one 40% of the time.

Tip: Method2 is most optimized for the value zero because it tests for it first.

C# program that tests switch and if

using System;
using System.Diagnostics;

class Program
{
    const int _max = 100000000;
    static void Main()
    {
	Method1(0); // JIT.
	Method2(0); // JIT.

	var s1 = Stopwatch.StartNew();
	for (int i = 0; i < _max; i++)
	{
	    Method1(0);
	    Method1(0);
	    Method1(0);
	    Method1(0);
	    Method1(0);
	    Method1(0);
	    Method1(1);
	    Method1(1);
	    Method1(1);
	    Method1(1);
	}
	s1.Stop();
	var s2 = Stopwatch.StartNew();
	for (int i = 0; i < _max; i++)
	{
	    Method2(0);
	    Method2(0);
	    Method2(0);
	    Method2(0);
	    Method2(0);
	    Method2(0);
	    Method2(1);
	    Method2(1);
	    Method2(1);
	    Method2(1);
	}
	s2.Stop();
	Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000 * 1000) /
	    _max).ToString("0.00 ns"));
	Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000 * 1000) /
	    _max).ToString("0.00 ns"));
	Console.Read();
    }

    static int Method1(int val)
    {
	switch (val)
	{
	    case 0:
		{
		    return 1;
		}
	    case 1:
		{
		    return 3;
		}
	    default:
		{
		    throw new Exception();
		}
	}
    }

    static int Method2(int val)
    {
	if (val == 0)
	{
	    return 1;
	}
	if (val == 1)
	{
	    return 3;
	}
	throw new Exception();
    }
}

Result: if faster

39.81 ns [switch]
18.79 ns [if]

We see that the two if-statements perform better. You save around 2 nanoseconds per method call. The intermediate language reveals that the switch-statement uses a "switch" opcode. The if-statements simply use branch opcodes.

Also: The exception logic was added to avoid inlining at the level of the JIT compiler.

JIT Method Test

Summary. In some cases, an equivalent switch statement is slower than an if-statement or chain of if-statements. Using frequency heuristics, you can optimize a fast path with an if-statement in many programs.