57005 or alive

Break and continue are fixed in Powershell v3 switch statements

Mar 27, 2012 powershell

In Powershell, the switch statement is really just syntactic sugar for a series of if statements (unlike in standard C-family compiled languages).  In order to shortcut evaluation of cases and prevent fallthrough, the break and continue keywords are available, and using them will immediately break execution out of the current switch case or statement.  If you want to prevent additional case evaluations and save precious cycles, it seems like a good practice to break execution as soon as possible.

Unfortunately, in Powershell v1 and v2, the break and continue statements were implemented under the covers by throwing an exception, which was then handled higher up the stack in the runtime in order to send execution to the correct place.  This is functionally just fine, but not very performant.  Exception processing is a very slow way to control flow of execution.  To illustrate this, we can look at the below example.

$samples = 100000
$cases = 10
$numbers = 1..$samples |%{ Get-Random -Min 0 -Max $cases }

$time = Measure-Command {
      switch ($numbers)
         1 { }
         2 { }
         3 { }
         4 { }
         5 { }
         6 { }
         7 { }
         8 { }
         9 { }
"Time (switch): $($time.TotalSeconds)"

$time = Measure-Command {
      switch ($numbers)
         1 { continue;}
         2 { continue;}
         3 { continue;}
         4 { continue;}
         5 { continue;}
         6 { continue;}
         7 { continue;}
         8 { continue;}
         9 { continue;}
"Time (switch w/ continue): $($time.TotalSeconds)"

The first test is doing more work - every element of $numbers is being checked against every case of the switch.  The second test bails out once it finds the first matching case, so it’s doing far fewer total comparisons.  However, because of the slow implementation of “continue”, the second test actually runs about 5 times slower on my machine.

Powershell v3 is in beta at the time of writing, and thankfully there has been a fix in this area (undocumented as far as I have seen).  Re-running the above code results in test #2 running about 40% faster than test #1, which is much closer to what we’d expect based only on the amount of case-checking performed.  Apparently the Powershell team has refactored this portion of the runtime to avoid exceptions as flow control devices, and it shows!

For more examples and discussion, check out these (long) technet forums threads which I participated in (I am the MSFT guy):

Switch -Regex in Powershell
Find value in array
Switch vs If/Else vs Hashtable of scriptblocks