Bassie
Bassie

Reputation: 10390

Switch vs If-Else Performance

I have the following If block which in a logon script which I am re-writing:

If ($distinguishedname -match 'Joe Bloggs') {
    Map-Drive 'X' "\\path\to\drive"
}
If ($distinguishedname -match 'Steve Bloggs') {
    Map-Drive 'X' "\\path\to\drive"
}
If ($distinguishedname -match 'Joe Jobs') {
    Map-Drive 'X' "\\path\to\drive"
}

Which obviously needs to be re-written as an If/Else statement (as each user only has 1 name!) However, I prefer the look of the following switch -Regex method:

switch -Regex ($distinguishedname) {
    'Joe Bloggs' {Map-Drive 'X' "\\path\to\drive"; break}
    'Steve Bloggs' {Map-Drive 'X' "\\path\to\drive"; break}
    'Joe Jobs' {Map-Drive 'X' "\\path\to\drive"; break}
}

My question is - would using a switch in this manner have any impact on the performance of this function? It must be better than the above (if/if/if), as not every possibility is evaluated each time, but would the switch be faster than an ifelse/ifelse/else?

Upvotes: 3

Views: 8843

Answers (2)

Bassie
Bassie

Reputation: 10390

I wrote this test to check if I could figure out which way is better using Measure-Command:

function switchtest {
    param($name)

    switch -Regex ($name) {
        $optionsarray[0] {
            Write-host $name
            break
        }
        $optionsarray[1] {
            Write-host $name
            break
        }
        $optionsarray[2] {
            Write-host $name
            break
        }
        $optionsarray[3] {
            Write-host $name
            break
        }
        $optionsarray[4] {
            Write-host $name
            break
        }
        default { }
    }
}
function iftest {
    param($name)

    If ($name -match $optionsarray[0]) {Write-host $name}
    ElseIf ($name -match $optionsarray[1]) {Write-host $name}
    ElseIf($name -match $optionsarray[2]) {Write-host $name}
    ElseIf($name -match $optionsarray[3]) {Write-host $name}
    ElseIf($name -match $optionsarray[4]) {Write-host $name}
}

$optionsarray = @('Joe Bloggs', 'Blog Joggs', 'Steve Bloggs', 'Joe Jobs', 'Steve Joggs')
for ($i=0; $i -lt 10000; $i++) {
    $iftime = 0
    $switchtime = 0

    $rand = Get-Random -Minimum 0 -Maximum 4
    $name = $optionsarray[$rand]

    $iftime = (Measure-Command {iftest $name}).Ticks
    $switchtime = (Measure-Command {switchtest $name}).Ticks

    Add-Content -Path C:\path\to\outfile\timetest.txt -Value "$switchtime`t$iftime"
}

Results

On average, this is how each function performed in 10,000 tests:

Switch - 11592.8566

IfElse - 15740.3281

The results were not the most consistent (sometimes switch was faster, sometimes ifelse was faster) but as switch is faster overall (on mean average) I will be using this instead of ifelse.

Would appreciate any feedback on this decision and my testing.

Upvotes: 8

Ryan
Ryan

Reputation: 1221

Typically, switch statements work by building a jump table in the assembly code and using that to determine the appropriate route instead of using comparators like if/else. That's why switch statements are faster. I believe that with strings, the compiler generates a hash code of the strings and uses that to implement the jump table so that the switch statement is still faster. So the switch statement should be faster than the if/if/if you have written above but it may not be since switch statements typically rely on the options being somewhat evenly spaced (e.g. 1 2 3 or 5 10 15).

With that being said, why don't you use an if/else-if/else-if instead of an if/if/if? That'll definitely be faster since not every option is evaluated each time.

Upvotes: 3

Related Questions