嵌套的其他语句与ElseIf语句的性能差异

时间:2013-08-29 12:58:31

标签: .net vb.net if-statement

同事和我对If陈述及其表现有不同意见。我的观点是应该使用If...ElseIf语句。他的观点是他在ElseIf中并没有相信,而是用嵌套的If语句写出所有内容。

我们假设在这种情况下不能使用案例陈述。我想知道的是,使用嵌套If..Else语句与使用If...ElseIf语句执行代码的效率如何。我知道代码可读性是一个因素,但不应该这样做。影响表现。

让我们看看下面的例子。

使用If Else:

If () then
    'Do something'
Else
    If () then
        'Do something'
    Else
        If () then
            'Do something'
        Else
            If () then
                'Do something'
            Else
                'Do something else'
            End If
        End If
    End If
End If

使用ElseIf:

If () then
    'Do something'
ElseIf () then
    'Do something'
ElseIf () then
    'Do something'
ElseIf () then
    'Do something'
Else
    'Do something else'
End If

我知道这是一个小规模的例子,但是可以说这样的块在整个应用程序中被大量使用。

两个代码部分之间是否存在任何性能差异,或者在编译应用程序后它们的执行几乎完全相同?

#### UPDATE #####

我创建了一个程序,用于测试x次函数的运行情况。

Public Class Form1

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    For i As Integer = 0 To 1000
        Run()
    Next
End Sub

Sub Run()

    Dim Time1Start As Integer = 0
    Dim Time1End As Integer = 0
    Dim Time2Start As Integer = 0
    Dim Time2End As Integer = 0

    Time2Start = CInt(DateTime.Now.ToString("fff"))
    runElse()
    Time2End = CInt(DateTime.Now.ToString("fff"))

    Time1Start = CInt(DateTime.Now.ToString("fff"))
    runElseIf()
    Time1End = CInt(DateTime.Now.ToString("fff"))

    TextBox1.Text += If(Time1End < Time1Start, Time1End + (1000 - Time1Start), Time1End - Time1Start) & vbTab & If(Time2End < Time2Start, Time2End + (1000 - Time2Start), Time2End - Time2Start) & vbCrLf
End Sub

Sub runElseIf()
    If sleep(10) Then
        'Do something'
    Else
        If sleep(10) Then
            'Do something'
        Else
            If sleep(10) Then
                'Do something'
            Else
                If sleep(10) Then
                    'Do something'
                Else
                    If sleep(10) Then
                        'Do something'
                    Else
                        If sleep(10) Then
                            'Do something'
                        Else
                            If sleep(10) Then
                                'Do something'
                            Else
                                If sleep(10) Then
                                    'Do something'
                                Else
                                    If sleep(10) Then
                                        'Do something'
                                    Else
                                        If sleep(10) Then
                                            'Do something'
                                        Else
                                            'Do something else'
                                        End If
                                    End If
                                End If
                            End If
                        End If
                    End If
                End If
            End If
        End If
    End If
End Sub

Sub runElse()
    If sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    ElseIf sleep(10) Then
        'Do something'
    Else
        'Do something else'
    End If
End Sub

Function sleep(ByVal ms As Integer) As Integer
    System.Threading.Thread.Sleep(ms)
    Return False
End Function

End Class

我运行程序,这是我的结果:
 500 Loops Average - ElseIf:108.248ms如果其他:106.507ms
1000循环平均值 - ElseIf:107.747ms如果其他:107.451ms(否则如果先运行)
1000次循环平均值 - ElseIf:107.683ms如果其他:107.076ms(ElseIf先运行)

也许数据集越大,数字就会发生变化,但在这3次试验中,If Else的表现实际上超出了ElseIf声明。

7 个答案:

答案 0 :(得分:8)

我已经反编译了两个,它似乎生成了相同的代码(使用ildasm)。这是一个非常简单的If语句,可能会得到不同的If不同的结果。我建议您对代码执行相同操作并查看。

Module Module1

    Sub Main()

        Dim a As Integer
        Dim i As Integer = 1

        If i = 1 Then
            a = 9
        ElseIf i = 2 Then
            a = 8
        ElseIf i = 3 Then
            a = 7
        Else
            a = 6
        End If

    End Sub

End Module



.method public static void  Main() cil managed
{
  .entrypoint
  .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       30 (0x1e)
  .maxstack  2
  .locals init ([0] int32 a,
           [1] int32 i)
  IL_0000:  ldc.i4.1
  IL_0001:  stloc.1
  IL_0002:  ldloc.1
  IL_0003:  ldc.i4.1
  IL_0004:  bne.un.s   IL_000b
  IL_0006:  ldc.i4.s   9
  IL_0008:  stloc.0
  IL_0009:  br.s       IL_001d
  IL_000b:  ldloc.1
  IL_000c:  ldc.i4.2
  IL_000d:  bne.un.s   IL_0013
  IL_000f:  ldc.i4.8
  IL_0010:  stloc.0
  IL_0011:  br.s       IL_001d
  IL_0013:  ldloc.1
  IL_0014:  ldc.i4.3
  IL_0015:  bne.un.s   IL_001b
  IL_0017:  ldc.i4.7
  IL_0018:  stloc.0
  IL_0019:  br.s       IL_001d
  IL_001b:  ldc.i4.6
  IL_001c:  stloc.0
  IL_001d:  ret
} // end of method Module1::Main

另一个

Module Module1

    Sub Main()

        Dim a As Integer
        Dim i As Integer = 1

        If i = 1 Then
            a = 9
        Else
            If i = 2 Then
                a = 8
            Else
                If i = 3 Then
                    a = 7
                Else
                    a = 6
                End If
            End If
        End If

    End Sub

End Module

.method public static void  Main() cil managed
{
  .entrypoint
  .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       30 (0x1e)
  .maxstack  2
  .locals init ([0] int32 a,
           [1] int32 i)
  IL_0000:  ldc.i4.1
  IL_0001:  stloc.1
  IL_0002:  ldloc.1
  IL_0003:  ldc.i4.1
  IL_0004:  bne.un.s   IL_000b
  IL_0006:  ldc.i4.s   9
  IL_0008:  stloc.0
  IL_0009:  br.s       IL_001d
  IL_000b:  ldloc.1
  IL_000c:  ldc.i4.2
  IL_000d:  bne.un.s   IL_0013
  IL_000f:  ldc.i4.8
  IL_0010:  stloc.0
  IL_0011:  br.s       IL_001d
  IL_0013:  ldloc.1
  IL_0014:  ldc.i4.3
  IL_0015:  bne.un.s   IL_001b
  IL_0017:  ldc.i4.7
  IL_0018:  stloc.0
  IL_0019:  br.s       IL_001d
  IL_001b:  ldc.i4.6
  IL_001c:  stloc.0
  IL_001d:  ret
} // end of method Module1::Main

我建议使用更容易阅读的那个。

答案 1 :(得分:4)

你担心错误的事情!!!

您编写的代码不是执行的代码。编译器将修改代码的结构以进行优化,并且它可以很好地处理这样的事情。也就是说,即使没有进行优化,速度差也无关紧要。

不要担心“它是否尽可能快?”而是担心“它是否足够快,并且可维护(可读)?”。

编译器和处理器非常擅长理解逻辑结构,但肉袋(人)却不是。无论何时编写代码,都应该尽量确保代码尽可能易于阅读。如果你发现它不易受到影响,那么你可以开始牺牲性能的可读性 - 但是这样做是出于偏执而被称为“过早优化”,这是一种很好的方法来制作不可维护的代码(并最终产生错误)。 / p>

话虽如此,这里有一些指导原则:

  • 有很多ifs / elses的方法是代码嗅觉(它们有一个高“cyclomatic complexity”。它表明单个方法做了很多这样做,这使得它难以阅读,维护,测试将你的方法分解成许多较小的方法。你可能仍然会得到一个相对较大的“控制”方法,它决定了该做什么 - 但是将实际做的任务委托给其他方法。

    < / LI>
  • 尽可能减少嵌套。

    如果存在导致简单return或退出的情况,请尝试 在序列的早期检查它们:(例如if (something) { return; })。

  • 将相关的检查组合在一起,并尝试将它们重构为自己的方法

  • 在测试中全面覆盖

答案 2 :(得分:2)

嗯,我相信这一切都取决于你正在检查的条件。

例如(伪代码):

if (A && B) {
} elseif (A && C) {
} elseif (A && D) {
}

在此示例中,所有if语句之间共享一个共同条件,这意味着重写以下内容可能更有效:

if (A) {
    if (B) {
    } elseif (C) {
    } elseif (D) {
    }
}

但是,如果缓存A条件的结果。性能提升可能很小。也许甚至存在由编译器执行的优化,因此您必须运行性能测试以确保执行时间的差异。

更重要的是,除非您正在编写一些性能关键代码,否则请始终尝试通过关注可读性来编写代码。几乎总有一种有效的方法可以在不损害效率的情况下扁平化条件陈述。

答案 3 :(得分:0)

这取决于您的代码。

if语句仅在满足条件时才被访问,否则将被忽略。 if elseif else块是相同的,但它正在测试许多条件,并且根据满足哪个条件,可能必须执行不同的操作才能获得您想要的结果。

我的意见是“这取决于案件”。

如果要执行代码中的所有内容,请使用elseif ..

如果你想忽略一些使用的话......

答案 4 :(得分:0)

当我拥有那么多if elseif时,我总是更喜欢切换机箱,但我知道它总是可行的。在这种情况下,ElseIf总是看起来更好,并且在后台使用else if实现,因此应该是相同的效果。

但!对于很多人,包括我的一些同事和老板,它是不可读的,因为它被视为if if if。我知道这很疯狂,但我认为这是一些心理学的事情....所以我明白你的同事来自哪里

答案 5 :(得分:0)

我进行了快速测试,发现 ElseIf的运行速度比嵌套If 稍快。请参阅下面的代码。

Imports System.Diagnostics
Module Module1

    Sub Main()
        Dim sw As New Stopwatch()
        Dim nestedTotal As Integer
        sw.Start()
        For i = 1 To 100000
            Nested()
        Next
        sw.Stop()
        nestedTotal = sw.ElapsedMilliseconds

        sw.Reset()

        Dim elsesTotal As Integer
        sw.Start()
        For i = 1 To 100000
            Elses()
        Next
        sw.Stop()
        elsesTotal = sw.ElapsedMilliseconds
        Console.WriteLine("Nested If:" & nestedTotal)
        Console.WriteLine("ElseIf:" & elsesTotal)
        Console.Read()
    End Sub

    Sub Nested()
        Dim num As Integer = GetNum()
        If num = 1 Then
            DoSomething()
        Else
            If num = 2 Then
                DoSomething()
            Else
                If num = 3 Then
                    DoSomething()
                Else
                    If num = 4 Then
                        DoSomething()
                    Else
                        DoSomething()
                    End If
                End If
            End If
        End If
    End Sub

    Sub DoSomething()
        Dim j As Integer
        For i = 1 To 1000
            j = i + j
        Next
    End Sub

    Sub Elses()
        Dim num As Integer = GetNum()
        If num = 1 Then
            DoSomething()
        ElseIf num = 2 Then
            DoSomething()
        ElseIf num = 3 Then
            DoSomething()
        ElseIf num = 4 Then
            DoSomething()
        Else
            DoSomething()
        End If
    End Sub

    Function GetNum()
        Dim Generator As System.Random = New System.Random()
        Return Generator.Next(1, 5)
    End Function
End Module

答案 6 :(得分:0)

从绩效角度来看,没有任何有意义的差异。对我来说,ElseIf的可读性显然更好。

Private Sub xelseif(tries As Integer)
    Dim foo As Integer
    For x As Integer = 1 To tries
        For y As Integer = 1 To 5 Step 4
            If y = 1 Then
                foo = y
            ElseIf y = 2 Then
            ElseIf y = 3 Then
            ElseIf y = 4 Then
            ElseIf y = 5 Then
                foo = y
            End If
        Next
    Next
End Sub

Private Sub xelse(tries As Integer)
    Dim foo As Integer
    For x As Integer = 1 To tries
        For y As Integer = 1 To 5 Step 4
            If y = 1 Then
                foo = y
            Else
                If y = 2 Then
                Else
                    If y = 3 Then
                    Else
                        If y = 4 Then
                        Else
                            If y = 5 Then
                                foo = y
                            End If
                        End If
                    End If
                End If
            End If
        Next
    Next
End Sub

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim stpw As New Stopwatch
    Dim tries As Integer = 1500000

    xelse(10)
    stpw.Restart()
    xelse(tries)
    stpw.Stop()
    Debug.WriteLine(stpw.ElapsedMilliseconds)

    xelseif(10)
    stpw.Restart()
    xelseif(tries)
    stpw.Stop()
    Debug.WriteLine(stpw.ElapsedMilliseconds)
End Sub