vb.net 如果 Mod = 0,是做多个 OrElse 更好还是单次检查

vb.net Is it better to do multiple OrElse's, or a single check if Mod = 0

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

第一种方式:

If month = 3 OrElse month = 6 OrElse month = 9 OrElse month = 12 Then
    'do stuff
End If

第二种方式:

If month Mod 3 = 0 Then
    'do stuff
End If

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

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

正如DaveDoknjas在上面的评论中所说,使用更清楚逻辑的方法。

如果你的逻辑决定你必须做某事,因为月份是一年中的第 3、6、9 或 12 个月,请使用:

If month = 3 OrElse month = 6 OrElse month = 9 OrElse month = 12 Then
    'do stuff
End If

但是,另一方面,如果您需要做某事因为月份数可以被 3 整除,请使用:

If month Mod 3 = 0 Then
    'do stuff
End If

性能上的差异非常小,不会引起注意。最后,当您需要它们时,它们都会评估为 True,因此这实际上取决于偏好以及您认为合乎逻辑和可读性的内容。

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

您在设计性能测试时必须小心:如果您只有评论部分 "executed" 那么在发布模式下它可能会被完全优化掉,即测试将不在 运行 的最终代码中,您不会为该测试计时。

你必须把一些无法优化的操作去掉,并且不要淹没时间。我使用了一个值的赋值,该值在使用时可能在处理器寄存器中,或者至少在处理器缓存中。

因此,您的测试可能看起来像

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

结果类似于

10.047
18.001
6.722
Tests in reverse order...
6.463
17.604
10.254

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