vb.net 执行多个 OrElse 更好,还是执行一次检查 Mod = 0 更好

mbo*_*007 0 vb.net performance boolean-logic modulus

有两种简单的方法可以检查一个月是否是季度的第一天。

第一种方式:

If month = 3 OrElse month = 6 OrElse month = 9 OrElse month = 12 Then
    'do stuff
End If
Run Code Online (Sandbox Code Playgroud)

第二种方式:

If month Mod 3 = 0 Then
    'do stuff
End If
Run Code Online (Sandbox Code Playgroud)

对我来说,它们都具有同等的可读性。尽管它们在功能上有所不同,但只要已知月份在 1 到 12 之间(含 1 和 12),它们的逻辑就相同。应该使用哪种方式?

在最坏的情况下,如果month = 12,则执行四次比较。进行模数和一次比较是否更快(并不是说这是显着的性能差异)?

And*_*ton 5

您表达了使用可读性能良好的测试的愿望。

在设计性能测试时必须小心:如果您只有注释作为要“执行”的部分,那么在发布模式下它可能会被完全优化,即测试不会出现在最终代码中已运行,您将不会对该测试进行计时。

您必须将一些无法优化的操作放入其中,并且不会淹没时序。我使用了一个值的赋值,该值在使用时可能位于处理器寄存器中,或者至少位于处理器缓存中。

所以,你的测试可能看起来像

Module Module1

    Sub Main()

        ' set up plenty of test data
        Dim rand As New Random
        Dim nTestMonths = 10000
        Dim testMonths(nTestMonths - 1) As Integer
        For i = 0 To nTestMonths - 1
            testMonths(i) = rand.Next(1, 13)
        Next

        ' time a lot of tests
        Dim sw As New Stopwatch
        Dim nTests = 100000

        Dim dummyVar As Integer

        ' run the tests in one order...
        sw.Restart()
        For i = 1 To nTests
            For j = 0 To nTestMonths - 1
                If testMonths(j) = 3 OrElse testMonths(j) = 6 OrElse testMonths(j) = 9 OrElse testMonths(j) = 12 Then
                    dummyVar = testMonths(j)
                End If

            Next
        Next
        sw.Stop()

        Console.WriteLine(sw.ElapsedMilliseconds / 1000)

        sw.Restart()

        For i = 1 To nTests
            For j = 0 To nTestMonths - 1
                If testMonths(j) Mod 3 = 0 Then
                    dummyVar = testMonths(j)
                End If

            Next
        Next
        sw.Stop()

        Console.WriteLine(sw.ElapsedMilliseconds / 1000)

        ' this test takes about nine times longer than the others
        ' so it is commented out.
        'Dim quarterStarts As New List(Of Integer) From {3, 6, 9, 12}

        'sw.Restart()

        'For i = 1 To nTests
        '   For j = 0 To nTestMonths - 1
        '       If quarterStarts.Contains(testMonths(j)) Then
        '           dummyVar = testMonths(j)
        '       End If

        '   Next
        'Next
        'sw.Stop()

        'Console.WriteLine(sw.ElapsedMilliseconds / 1000)

        sw.Restart()

        For i = 1 To nTests
            For j = 0 To nTestMonths - 1
                Select Case testMonths(j)
                    Case 3, 6, 9, 12
                        dummyVar = testMonths(j)
                End Select
            Next
        Next
        sw.Stop()

        Console.WriteLine(sw.ElapsedMilliseconds / 1000)

        ' now run the tests in a different order...
        Console.WriteLine("Tests in reverse order...")
        sw.Restart()

        For i = 1 To nTests
            For j = 0 To nTestMonths - 1
                Select Case testMonths(j)
                    Case 3, 6, 9, 12
                        dummyVar = testMonths(j)
                End Select
            Next
        Next
        sw.Stop()

        Console.WriteLine(sw.ElapsedMilliseconds / 1000)

        'sw.Restart()

        'For i = 1 To nTests
        '   For j = 0 To nTestMonths - 1
        '       If quarterStarts.Contains(testMonths(j)) Then
        '           dummyVar = testMonths(j)
        '       End If

        '   Next
        'Next
        'sw.Stop()

        'Console.WriteLine(sw.ElapsedMilliseconds / 1000)

        sw.Restart()

        For i = 1 To nTests
            For j = 0 To nTestMonths - 1
                If testMonths(j) Mod 3 = 0 Then
                    dummyVar = testMonths(j)
                End If

            Next
        Next
        sw.Stop()

        Console.WriteLine(sw.ElapsedMilliseconds / 1000)

        sw.Restart()
        For i = 1 To nTests
            For j = 0 To nTestMonths - 1
                If testMonths(j) = 3 OrElse testMonths(j) = 6 OrElse testMonths(j) = 9 OrElse testMonths(j) = 12 Then
                    dummyVar = testMonths(j)
                End If

            Next
        Next
        sw.Stop()

        Console.WriteLine(sw.ElapsedMilliseconds / 1000)
        Console.ReadLine()


    End Sub

End Module
Run Code Online (Sandbox Code Playgroud)

这会导致类似的结果

10.047
18.001
6.722
Tests in reverse order...
6.463
17.604
10.254
Run Code Online (Sandbox Code Playgroud)

所以你可以看到The_Black_Smurf提出的使用Select Case语句的建议既有很好的可读性,又恰好是最快的。