【问题标题】:VB.Net Function Optimization (SSRS Report Code)VB.Net函数优化(SSRS报告代码)
【发布时间】:2010-01-14 19:38:42
【问题描述】:

最近遇到如下代码,想优化一下:

Public Shared Function ComputeLabel(ByVal Action As Integer, ByVal Flag1 As Boolean, ByVal Flag2 As Boolean) As String
   Dim Prefix As String = ""

   If Flag2 Then
      Prefix = "Conditional "
   ElseIf Flag1 Then
      Prefix = "Held "
   End If

   Select Case Action
      Case 0
         Return ""
      Case 1
         Return Prefix & "Cancelled"
      Case 2
         Return Prefix & "Discontinued"
      Case 3
         Return Prefix & "Suspended"
      Case 4
         Return Prefix & "Unsuspended"
      Case 6
         Return Prefix & "Collected"
      Case 7
         Return Prefix & "Released from Hold"
      Case 8
         Return Prefix & "Modified"
      Case 9
         Return Prefix & "Discontinued for the Future"
      Case 10
         Return Prefix & "Verified"
      Case 11
         Return Prefix & "Modified And Verified"
      Case 12
         Return "Hold " & Prefix & "Cancelled"
      Case Else
         Return ""
   End Select
End Function

请注意,Action 0 是最常见的情况。

好的,我已经稍微清理了这个函数——它使用了一个变量并在最后返回它,使用 Return 似乎更好。但另外,我认为在报表执行开始时构建一个数组会更好的代码,然后每次调用此函数时只访问数组元素,而不是使用 Select 语句。但是案例 12 让事情变得更加复杂(如您所见,它在中间而不是开头添加了前缀。)

你认为最好的方法是:

  • 一次为三种情况构建一个 39 元素的数组:

    Private Shared OrderActions() As String = {"", "Cancelled", ...}
    

    然后在函数中像这样访问它:

    If Action < 0 OrElse Action >= 13 Then Return ""
    Return OrderActions(Action - Flag2 * 13 - (Flag1 AndAlso Not Flag2) * 26)
    
  • 使用 13 元素数组和替换(类似于 Return Replace(LabelList(Action), "{Prefix}", Prefix)?)

  • 使用 12 元素数组和 Action 12 的特殊情况。

  • 其他我没想到的。

?

更新 1:我的格式已关闭,因此选项可能不清楚。现在应该更易读了。

更新 2:我明白你的意思,从性能的角度来看,完全扩展所有情况并使用简单的变量赋值可能是最快的。所以......假设最高速度不是优先事项,但整体优雅是(干净的代码和速度的组合)。人们也有机会对此发表看法吗?我会投票给所有对问题的各个方面提供合理帮助的人。

更新 3:我忽略的另一个考虑因素是一些没有经验的程序员将长期维护这一点,因此它确实需要易于理解。从这个角度来看,我想我尝试缩短代码的示例确实不好。

更新 4:测试为王!!!一旦我受到启发去做一些速度测试,我得到了一些有趣的结果。请参阅下面的答案。

【问题讨论】:

  • 与你正在做的其他事情相比,任何类型的字符串操作都很慢,所以我会立即排除。我想像你提到的那样在其中的每个案例中构建一个 39 元素的数组将是唯一可能比我的方法更快的选项(或者它可能不会)。然而,一个包含复杂查找的 39 个元素的数组会比我那可怕的代码更令人困惑。
  • 三个 13 元素数组,有条件选择数组是最快的。将带有数学的布尔逻辑转换为单个数组中的索引会花费更多。

标签: vb.net optimization reporting-services


【解决方案1】:

如果这是一个瓶颈并且速度是一个优先事项,那么我的第一个建议是通过复制大部分逻辑来消除字符串连接。这将使函数变得更大,可读性更差,但也许这对速度来说是值得的......

Public Shared Function ComputeLabel(ByVal Action As Integer, ByVal Flag1 As Boolean, ByVal Flag2 As Boolean) As String
   Select Case nHVCOrderAction
        Case 0
            Return ""
        Case 1
            If Flag2 Then
                Return "Conditional Cancelled"
            ElseIf Flag1 Then
                Return "Held Cancelled"
            Else
                Return "Cancelled"
            End If
        Case 2
            If Flag2 Then
                Return "Conditional Discontinued"
            ElseIf Flag1 Then
                Return "Held Discontinued"
            Else
                Return "Discontinued"
            End If
        ' And so on...
   End Select
End Function

相对而言,您的代码中的字符串连接可能会比您在此处进行的整数和布尔比较操作要慢。因此,通过足够的重复次数,您应该会看到这种方法的速度明显提高。

更新:

我编写了一个快速而肮脏的 VB.NET 控制台应用程序来测试您的原始代码与我的代码。这是我为每个运行的循环(我没有写出所有可能的组合,但你明白了):

    Dim sw As New Stopwatch()
    sw.Start()

    For i As Integer = 0 To 10000000
        str = ComputeLabel(0, True, False)
        str = ComputeLabel(1, False, False)
        str = ComputeLabel(0, False, False)
        str = ComputeLabel(2, False, False)
        str = ComputeLabel(1, False, True)
        str = ComputeLabel(2, True, True)
        str = ComputeLabel(4, False, True)
        str = ComputeLabel(7, True, True)
        str = ComputeLabel(12, False, True)
    Next

    sw.Stop()
    Console.WriteLine(sw.ElapsedMilliseconds & " ms")

以下是时间:

旧方法:6189 毫秒

新方法:1374 毫秒

因此,通过删除字符串连接并扩展每种情况的条件,速度提高了 5 倍。当然,您可能已经注意到循环运行了 1000 万次……这已经很多了。

更新:

我编写了另一个基准应用程序来完全模仿你自己的:

Module Module1

        Sub Main()

            Dim str As String = ""
            Dim sw As New Stopwatch()

            ' Test 1
            sw.Start()
            For i As Integer = 0 To 100000
                 For j As Integer = -1 To 13
                        str = ComputeLabel_X(j, False, False)
                        str = ComputeLabel_X(j, True, False)
                        str = ComputeLabel_X(j, False, True)
                 Next
            Next
            sw.Stop()
            Console.WriteLine("Old method: " & sw.ElapsedMilliseconds & " ms")
            sw.Reset()

            ' Test 2
            sw.Start()
            For i As Integer = 0 To 100000
                 For j As Integer = -1 To 13
                        str = ComputeLabel_Y(j, False, False)
                        str = ComputeLabel_Y(j, True, False)
                        str = ComputeLabel_Y(j, False, True)
                 Next
            Next
            sw.Stop()
            Console.WriteLine("New method: " & sw.ElapsedMilliseconds & " ms")
            sw.Reset()

        End Sub

        Public Function ComputeLabel_X(ByVal Action As Integer, ByVal Held As Boolean, ByVal Conditional As Boolean) As String
             Dim Prefix As String = ""

             If Conditional Then
                    Prefix = "Conditional "
             ElseIf Held Then
                    Prefix = "Held "
             End If

             Select Case Action
                    Case 0
                         Return ""
                    Case 1
                         Return Prefix & "Cancelled"
                    Case 2
                         Return Prefix & "Discontinued"
                    Case 3
                         Return Prefix & "Suspended"
                    Case 4
                         Return Prefix & "Unsuspended"
                    Case 6
                         Return Prefix & "Collected"
                    Case 7
                         Return Prefix & "Released from Hold"
                    Case 8
                         Return Prefix & "Modified"
                    Case 9
                         Return Prefix & "Discontinued for the Future"
                    Case 10
                         Return Prefix & "Verified"
                    Case 11
                         Return Prefix & "Modified And Verified"
                    Case 12
                         Return "Hold " & Prefix & "Cancelled"
                    Case Else
                         Return ""
             End Select
        End Function

        Public Function ComputeLabel_Y(ByVal Action As Integer, ByVal Held As Boolean, ByVal Conditional As Boolean) As String
             Select Case Action
                    Case 0
                        Return ""
                    Case 1
                        If Conditional Then
                            Return "Conditional Cancelled"
                        ElseIf Held Then
                            Return "Held Cancelled"
                        Else
                            Return "Cancelled"
                        End If
                    Case 2
                        If Conditional Then
                            Return "Conditional Discontinued"
                        ElseIf Held Then
                            Return "Held Discontinued"
                        Else
                            Return "Discontinued"
                        End If
                    Case 3
                        If Conditional Then
                            Return "Conditional Suspended"
                        ElseIf Held Then
                            Return "Held Suspended"
                        Else
                            Return "Suspended"
                        End If
                    Case 4
                        If Conditional Then
                            Return "Conditional Unsuspended"
                        ElseIf Held Then
                            Return "Held Unsuspended"
                        Else
                            Return "Unsuspended"
                        End If
                    Case 6
                        If Conditional Then
                            Return "Conditional Collected"
                        ElseIf Held Then
                            Return "Held Collected"
                        Else
                            Return "Collected"
                        End If
                    Case 7
                        If Conditional Then
                            Return "Conditional Released from Hold"
                        ElseIf Held Then
                            Return "Held Released from Hold"
                        Else
                            Return "Released from Hold"
                        End If
                    Case 8
                        If Conditional Then
                            Return "Conditional Modified"
                        ElseIf Held Then
                            Return "Held Modified"
                        Else
                            Return "Modified"
                        End If
                    Case 9
                        If Conditional Then
                            Return "Conditional Discontinued for the Future"
                        ElseIf Held Then
                            Return "Held Discontinued for the Future"
                        Else
                            Return "Discontinued for the Future"
                        End If
                    Case 10
                        If Conditional Then
                            Return "Conditional Verified"
                        ElseIf Held Then
                            Return "Held Verified"
                        Else
                            Return "Verified"
                        End If
                    Case 11
                        If Conditional Then
                            Return "Conditional Modified And Verified"
                        ElseIf Held Then
                            Return "Held Modified And Verified"
                        Else
                            Return "Modified And Verified"
                        End If
                    Case 12
                        If Conditional Then
                            Return "Hold Conditional Cancelled"
                        ElseIf Held Then
                            Return "Hold Held Cancelled"
                        Else
                            Return "Hold Cancelled"
                        End If
                    Case Else
                        Return ""
             End Select
        End Function
End Module

使用我的代码,我的结果再次变得更快:

旧方法:169 毫秒

新方法:30 毫秒

我当然是在没有调试的情况下运行 (Ctrl F5)。现在我使用的是 3.0 GHz AMD 四核。

【讨论】:

  • 嗯,感谢您的回复。速度不是一个问题,像这样一路扩展很有用。我总是喜欢考虑速度,但不要在不需要时扭曲代码。您是否有一些示例代码或用于进行此类速度测试的链接?
  • 好吧,我实际上认为您的原始代码是最优雅的解决方案。我的……很长,但很有效。关于基准测试:我刚刚在上面的示例中添加了 StopWatch 开始/停止代码。我只是更喜欢在 Visual Studio 中创建一个控制台应用程序项目来执行此操作,因为这是测试此类算法的一种非常简单的方法。
  • 非常感谢您的帮助。您介意批评我发布的新答案吗?
  • 太糟糕了,我不能对共享答案给予信任。你和我互动最多,我没有办法奖励它。但是,看起来数组查找比 case 语句更快。
  • 一切都好。在我的 OpenGL 时代,我是一个痴迷的优化器,但有时我做的还不够。我很高兴能提供帮助。
【解决方案2】:

实际上,如果将它们放入数组中,使用以下方法可以将执行时间从我机器上的 6589ms 提高到 1174ms:

以下内容来自控制台应用程序,但您大致了解。数组加载一次,然后根据需要访问多次,在这种情况下,我使用了 Steve Wortham 作为测试发布的 for 循环。

Dim _ConditionalLabels(12) As String
Dim _HeldLabels(12) As String

Sub Main()
    Dim sw As New Stopwatch()
    sw.Start()

    _ConditionalLabels(0) = ""
    _ConditionalLabels(1) = "Conditional Cancelled"
    _ConditionalLabels(2) = "Conditional Discontinued"
    _ConditionalLabels(3) = "Conditional Suspended"
    _ConditionalLabels(4) = "Conditional Unsuspended"
    _ConditionalLabels(6) = "Conditional Collected"
    _ConditionalLabels(7) = "Conditional Released from Hold"
    _ConditionalLabels(8) = "Conditional Modified"
    _ConditionalLabels(9) = "Conditional Discontinued for the Future"
    _ConditionalLabels(10) = "Conditional Verified"
    _ConditionalLabels(11) = "Conditional Modified And Verified"
    _ConditionalLabels(12) = "Hold Conditional Cancelled"

    _HeldLabels(0) = ""
    _HeldLabels(1) = "Held Cancelled"
    _HeldLabels(2) = "Held Discontinued"
    _HeldLabels(3) = "Held Suspended"
    _HeldLabels(4) = "Held Unsuspended"
    _HeldLabels(6) = "Held Collected"
    _HeldLabels(7) = "Held Released from Hold"
    _HeldLabels(8) = "Held Modified"
    _HeldLabels(9) = "Held Discontinued for the Future"
    _HeldLabels(10) = "Held Verified"
    _HeldLabels(11) = "Held Modified And Verified"
    _HeldLabels(12) = "Hold Held Cancelled"

    Dim str As String = ""
    For i As Integer = 0 To 10000000
        str = ComputeLabel(0, True, False)
        str = ComputeLabel(1, False, False)
        str = ComputeLabel(0, False, False)
        str = ComputeLabel(2, False, False)
        str = ComputeLabel(1, False, True)
        str = ComputeLabel(2, True, True)
        str = ComputeLabel(4, False, True)
        str = ComputeLabel(7, True, True)
        str = ComputeLabel(12, False, True)
    Next

    sw.Stop()
    Console.WriteLine(sw.ElapsedMilliseconds & " ms")
    Console.Read()
End Sub

Public Function ComputeLabel(ByVal Action As Integer, ByVal Held As Boolean, ByVal Conditional As Boolean) As String
    If Conditional Then
        Return _ConditionalLabels(Action)
    ElseIf Held Then
        Return _HeldLabels(Action)
    End If
End Function

【讨论】:

  • 感谢您加入,Russ。请注意,应该有 3 组标签,因为标志都可以为假。你有什么想法是你做的方式更快还是_ConditionalLabels = {"1", "2", "3"}更快?
  • 我会制作 3 组数组以保持每个数组的数量通常很小。但是给一个多维数组试一试,看看性能如何。可以忽略不计。
  • Russ,我问的是如何填充数组,一次使用 { } 或像你一样分配每个成员。此外,根据我最近读到的内容,多维数组(任何一种)都会比带索引计算的平面数组慢。另外,为什么数组中的项目数与取消引用索引的速度有关?
  • 啊,我也喜欢这种方法。一旦添加第三个条件和数组,它的性能应该非常接近我的。
  • 最后一件事:您的代码没有进行边界检查来处理“Else”条件。我想我会自己测试一些速度!
【解决方案3】:

你不能优化它,它已经很高效了。你可以让它更具可读性,Flag1 和 Flag2 绝对应该重命名为 Held 和 Conditional。

【讨论】:

  • 谢谢...在原始代码中,它们的名称是恰当的。我混淆了一些东西。很抱歉把扳手扔进去了。你的名字不是韦恩,是吗?
【解决方案4】:

这是我自己的速度测试结果(最后)。

在我的测试中,我使用了以下代码。我使用了 100 万次迭代来缩短等待时间。 -1 到 13 是给一些越界的工作。当需要阵列设置时,它包含在总时间中,但只完成一次。每个函数都有自己的调用过程,名称为 (X) 硬编码:

Dim str As String = ""
For i As Integer = 0 To 1000000
   For j As Integer = -1 To 13
      str = ComputeLabel_X(j, False, False)
      str = ComputeLabel_X(j, True, False)
      str = ComputeLabel_X(j, False, True)
   Next
Next

在使用 F5(出错时中断代码)和 Ctrl-F5(在调试器之外运行)运行代码时,我也得到了不同的结果。我猜第二个对 SSRS 代码环境更有效,因为没有任何东西会附加到进程来调试它。

所有结果都无需调试 (Ctrl-F5) 即可编译。

  • Russ:613 毫秒(添加了边界检查)
  • Erik:614 毫秒(与 Russ 相同,但数组填充为数组文字 {} 而不是单个语句)
  • Erik2:526 毫秒(0 到 12,额外的 0 到 2,无边界检查)
  • 史蒂夫:660 毫秒
  • Steve2:873 毫秒(删除个别 If 语句的 ElseIf)
  • 新:2977 毫秒(我之前回答的第一个想法)
  • 初始发布:3915 毫秒 * - 修改为正确(小了 10 倍)
  • 原文:3947 ms(你从未见过的版本,我优化后在这里发布的版本)
  • 选择:11068 毫秒
  • BigArray:12565 毫秒(用数学计算大数组的索引)

尽管较高值的执行时间可能会波动多达 100 毫秒,但排名往往保持一致,除了不断交换的 Russ 和 Erik 版本。

要点:

  • 构建一次数组是无关紧要的。将其作为单独的语句或作为数组文字 {} 是相同的。

  • 对数组方法进行边界检查的成本增加了 20%。

  • 直观地扩展整个事物似乎应该是最快的,但事实并非如此。我不知道为什么。也许它与处理器缓存行大小和预加载权衡有关,或者类似的东西。

  • 我从原始函数对我在问题中发布的函数所做的唯一真正更改是:1) 从每个 case 语句返回,而不是将字符串分配给变量并在最后返回(加上删除变量),2)交换独立的 If Flag 语句顺序并将第二个 If 更改为 ElseIf。 1% 的提升是微不足道的

  • 似乎我应该能够从我列为“新”的版本(我发布的另一个答案中的第一个查询)表现如此糟糕这一事实中概括出一些东西。它是更长的字符串吗?是不是无论在程序的哪个位置返回都一样快,但是退出Case语句执行更多指令却很慢?

  • Russ 的数组版本最快。数组查找比使用字符串连接的 case 语句更快。

  • 此时我不知道如何解释为什么新版本更快。

  • Choose 功能超级超级慢。

由于这些测试,我必须将这个问题的答案授予声称我无法优化给定代码的 nobugz。到目前为止,他是对的!

更新:对于我在测试初始发布版本的迭代次数上留下零的错误,我感到非常抱歉。事情已经得到纠正。

附录:(更正的)测试代码:

Module Module1

   Dim _Labels(12) As String
   Dim _ConditionalLabels(12) As String
   Dim _HeldLabels(12) As String

   Dim Labels() As String
   Dim ConditionalLabels() As String
   Dim HeldLabels() As String

   Dim OrderLabelsBigArray(38) As String

   Sub Main()
      Dim sw As New Stopwatch()
      sw.Start()
      ComputeLabelsFirstPosted()
      sw.Stop()
      Console.WriteLine("FirstPosted " & sw.ElapsedMilliseconds & " ms")

      sw.Reset()
      sw.Start()
      ComputeLabelsRuss()
      sw.Stop()
      Console.WriteLine("Russ " & sw.ElapsedMilliseconds & " ms")

      sw.Reset()
      sw.Start()
      ComputeLabelsErik()
      sw.Stop()
      Console.WriteLine("Erik " & sw.ElapsedMilliseconds & " ms")

      sw.Reset()
      sw.Start()
      ComputeLabelsErik2()
      sw.Stop()
      Console.WriteLine("Erik2 " & sw.ElapsedMilliseconds & " ms")

      sw.Reset()
      sw.Start()
      ComputeLabelsBigArray()
      sw.Stop()
      Console.WriteLine("BigArray " & sw.ElapsedMilliseconds & " ms")

      sw.Reset()
      sw.Start()
      ComputeLabelsSteve()
      sw.Stop()
      Console.WriteLine("Steve " & sw.ElapsedMilliseconds & " ms")

      sw.Reset()
      sw.Start()
      ComputeLabelsSteve2()
      sw.Stop()
      Console.WriteLine("Steve2 " & sw.ElapsedMilliseconds & " ms")

      sw.Reset()
      sw.Start()
      ComputeLabelsNew()
      sw.Stop()
      Console.WriteLine("New " & sw.ElapsedMilliseconds & " ms")

      sw.Reset()
      sw.Start()
      ComputeLabelsChoose()
      sw.Stop()
      Console.WriteLine("Choose " & sw.ElapsedMilliseconds & " ms")

      sw.Reset()
      sw.Start()
      ComputeLabelsOriginal()
      sw.Stop()
      Console.WriteLine("Original " & sw.ElapsedMilliseconds & " ms")

      Console.Read()
   End Sub

   Public Sub ComputeLabelsFirstPosted()
      Dim str As String = ""
      For i As Integer = 0 To 1000000
         For j As Integer = -1 To 13
            str = ComputeLabelFirstPosted(j, False, False)
            str = ComputeLabelFirstPosted(j, True, False)
            str = ComputeLabelFirstPosted(j, False, True)
         Next
      Next
   End Sub

   Public Function ComputeLabelFirstPosted(ByVal Action As Integer, ByVal IsHeld As Boolean, ByVal IsConditional As Boolean) As String
      Dim Prefix As String = ""

      If IsConditional Then
         Prefix = "Conditional "
      ElseIf IsHeld Then
         Prefix = "Held "
      End If

      Select Case Action
         Case 0
            Return ""
         Case 1
            Return Prefix & "Cancelled"
         Case 2
            Return Prefix & "Discontinued"
         Case 3
            Return Prefix & "Suspended"
         Case 4
            Return Prefix & "Unsuspended"
         Case 6
            Return Prefix & "Collected"
         Case 7
            Return Prefix & "Released from Hold"
         Case 8
            Return Prefix & "Modified"
         Case 9
            Return Prefix & "Discontinued for the Future"
         Case 10
            Return Prefix & "Verified"
         Case 11
            Return Prefix & "Modified And Verified"
         Case 12
            Return "Hold " & Prefix & "Cancelled"
         Case Else
            Return ""
      End Select
   End Function

   Sub ComputeLabelsRuss()
      _Labels(0) = ""
      _Labels(1) = "Cancelled"
      _Labels(2) = "Discontinued"
      _Labels(3) = "Suspended"
      _Labels(4) = "Unsuspended"
      _Labels(6) = "Collected"
      _Labels(7) = "Released from Hold"
      _Labels(8) = "Modified"
      _Labels(9) = "Discontinued for the Future"
      _Labels(10) = "Verified"
      _Labels(11) = "Modified And Verified"
      _Labels(12) = "Hold Cancelled"

      _ConditionalLabels(0) = ""
      _ConditionalLabels(1) = "Conditional Cancelled"
      _ConditionalLabels(2) = "Conditional Discontinued"
      _ConditionalLabels(3) = "Conditional Suspended"
      _ConditionalLabels(4) = "Conditional Unsuspended"
      _ConditionalLabels(6) = "Conditional Collected"
      _ConditionalLabels(7) = "Conditional Released from Hold"
      _ConditionalLabels(8) = "Conditional Modified"
      _ConditionalLabels(9) = "Conditional Discontinued for the Future"
      _ConditionalLabels(10) = "Conditional Verified"
      _ConditionalLabels(11) = "Conditional Modified And Verified"
      _ConditionalLabels(12) = "Hold Conditional Cancelled"

      _HeldLabels(0) = ""
      _HeldLabels(1) = "Held Cancelled"
      _HeldLabels(2) = "Held Discontinued"
      _HeldLabels(3) = "Held Suspended"
      _HeldLabels(4) = "Held Unsuspended"
      _HeldLabels(6) = "Held Collected"
      _HeldLabels(7) = "Held Released from Hold"
      _HeldLabels(8) = "Held Modified"
      _HeldLabels(9) = "Held Discontinued for the Future"
      _HeldLabels(10) = "Held Verified"
      _HeldLabels(11) = "Held Modified And Verified"
      _HeldLabels(12) = "Hold Held Cancelled"

      Dim str As String = ""
      For i As Integer = 0 To 1000000
         For j As Integer = -1 To 13
            str = ComputeLabelRuss(j, False, False)
            str = ComputeLabelRuss(j, True, False)
            str = ComputeLabelRuss(j, False, True)
         Next
      Next
   End Sub

   Public Function ComputeLabelRuss(ByVal Action As Integer, ByVal Held As Boolean, ByVal Conditional As Boolean) As String
      If Action < 0 OrElse Action > 12 Then Return ""
      If Conditional Then Return _ConditionalLabels(Action)
      If Held Then Return _HeldLabels(Action)
      Return _Labels(Action)
   End Function

   Public Sub ComputeLabelsNew()
      Dim str As String = ""
      For i As Integer = 0 To 1000000
         For j As Integer = -1 To 13
            str = ComputeLabelNew(j, False, False)
            str = ComputeLabelNew(j, True, False)
            str = ComputeLabelNew(j, False, True)
         Next
      Next
   End Sub

   Public Function ComputeLabelNew(ByVal Action As Integer, ByVal IsHeld As Boolean, ByVal IsConditional As Boolean) As String
      Dim Status As String = ""

      Select Case Action
         Case 0
            Return ""
         Case 1
            Status = "Cancelled"
         Case 2
            Status = "Discontinued"
         Case 3
            Status = "Suspended"
         Case 4
            Status = "Unsuspended"
         Case 6
            Status = "Collected"
         Case 7
            Status = "Released from Hold"
         Case 8
            Status = "Modified"
         Case 9
            Status = "Discontinued for the Future"
         Case 10
            Status = "Verified"
         Case 11
            Status = "Modified And Verified"
         Case 12
            If IsConditional Then Return "Hold Conditional Cancelled"
            If IsHeld Then Return "Hold Held Cancelled"
            Return "Hold Cancelled"
         Case Else
            Return ""
      End Select
      If IsConditional Then Return "Conditional " & Status
      If IsHeld Then Return "Held " & Status
      Return Status
   End Function

   Sub ComputeLabelsErik()
      Labels = New String() {"", "Cancelled", "Discontinued", "Suspended", "Unsuspended", "", "Collected", "Released from Hold", "Modified", "Discontinued for the Future", "Verified", "Modified And Verified", "Hold Cancelled"}
      ConditionalLabels = New String() {"", "Conditional Cancelled", "Conditional Discontinued", "Conditional Suspended", "Conditional Unsuspended", "Conditional ", "Conditional Collected", "Conditional Released from Hold", "Conditional Modified", "Conditional Discontinued for the Future", "Conditional Verified", "Conditional Modified And Verified", "Hold  Cancelled"}
      HeldLabels = New String() {"", "Held Cancelled", "Held Discontinued", "Held Suspended", "Held Unsuspended", "Held ", "Held Collected", "Held Released from Hold", "Held Modified", "Held Discontinued for the Future", "Held Verified", "Held Modified And Verified", "Hold  Cancelled"}

      Dim str As String = ""
      For i As Integer = 0 To 1000000
         For j As Integer = -1 To 13
            str = ComputeLabelErik(j, False, False)
            str = ComputeLabelErik(j, True, False)
            str = ComputeLabelErik(j, False, True)
         Next
      Next
   End Sub

   Public Function ComputeLabelErik(ByVal Action As Integer, ByVal Held As Boolean, ByVal Conditional As Boolean) As String
      If Action < 0 OrElse Action > 12 Then Return ""
      If Conditional Then Return ConditionalLabels(Action)
      If Held Then Return HeldLabels(Action)
      Return Labels(Action)
   End Function

   Sub ComputeLabelsErik2()
      Dim str As String = ""
      For i As Integer = 0 To 1000000
         For j As Integer = 0 To 12
            str = ComputeLabelErik2(j, False, False)
            str = ComputeLabelErik2(j, True, False)
            str = ComputeLabelErik2(j, False, True)
         Next
         For j As Integer = 1 To 2
            str = ComputeLabelErik2(j, False, False)
            str = ComputeLabelErik2(j, True, False)
            str = ComputeLabelErik2(j, False, True)
         Next
      Next
   End Sub

   Public Function ComputeLabelErik2(ByVal Action As Integer, ByVal Held As Boolean, ByVal Conditional As Boolean) As String
      If Conditional Then Return ConditionalLabels(Action)
      If Held Then Return HeldLabels(Action)
      Return Labels(Action)
   End Function

   Public Sub ComputeLabelsOriginal()
      Dim str As String = ""
      For i As Integer = 0 To 1000000
         For j As Integer = -1 To 13
            str = ComputeLabelOriginal(j, False, False)
            str = ComputeLabelOriginal(j, True, False)
            str = ComputeLabelOriginal(j, False, True)
         Next
      Next
   End Sub

   Public Function ComputeLabelOriginal(ByVal Action As Integer, ByVal bIsHeld As Boolean, _
   ByVal bIsConditional As Boolean) As String

      Dim strReprintLabel As String = ""
      Dim strOrderActionPrefix As String = ""

      If (bIsHeld) Then
         strOrderActionPrefix = "Held "
      End If

      If (bIsConditional) Then
         strOrderActionPrefix = "Conditional "
      End If

      Select Case Action
         Case 0   ' Normal Order
            strReprintLabel = ""
         Case 1
            strReprintLabel = strOrderActionPrefix & "Order Cancelled"
         Case 2
            strReprintLabel = strOrderActionPrefix & "Order Discontinued"
         Case 3
            strReprintLabel = strOrderActionPrefix & "Order Suspended"
         Case 4
            strReprintLabel = strOrderActionPrefix & "Order Unsuspended"
         Case 6
            strReprintLabel = strOrderActionPrefix & "Order Collected"
         Case 7
            strReprintLabel = strOrderActionPrefix & "Order Released from Hold"
         Case 8
            strReprintLabel = strOrderActionPrefix & "Order Modified"
         Case 9
            strReprintLabel = strOrderActionPrefix & "Order Discontinued for the Future"
         Case 10
            strReprintLabel = strOrderActionPrefix & "Order Verified"
         Case 11
            strReprintLabel = strOrderActionPrefix & "Order Modified And Verified"
         Case 12
            strReprintLabel = "Hold " & strOrderActionPrefix & "Order Cancelled"
         Case Else
            strReprintLabel = ""
      End Select

      Return strReprintLabel
   End Function

   Sub ComputeLabelsSteve2()
      Dim str As String = ""
      For i As Integer = 0 To 1000000
         For j As Integer = -1 To 13
            str = ComputeLabelSteve2(j, False, False)
            str = ComputeLabelSteve2(j, True, False)
            str = ComputeLabelSteve2(j, False, True)
         Next
      Next
   End Sub

   Public Function ComputeLabelSteve2(ByVal Action As Integer, ByVal IsHeld As Boolean, ByVal IsConditional As Boolean) As String
      Select Case Action
         Case 0
            Return ""
         Case 1
            If IsConditional Then Return "Conditional Cancelled"
            If IsHeld Then Return "Held Cancelled"
            Return "Cancelled"
         Case 2
            If IsConditional Then Return "Conditional Discontinued"
            If IsHeld Then Return "Held Discontinued"
            Return "Discontinued"
         Case 3
            If IsConditional Then Return "Conditional Suspended"
            If IsHeld Then Return "Held Suspended"
            Return "Suspended"
         Case 4
            If IsConditional Then Return "Conditional Unsuspended"
            If IsHeld Then Return "Held Unsuspended"
            Return "Unsuspended"
         Case 6
            If IsConditional Then Return "Conditional Collected"
            If IsHeld Then Return "Held Collected"
            Return "Collected"
         Case 7
            If IsConditional Then Return "Conditional Released from Hold"
            If IsHeld Then Return "Held Released from Hold"
            Return "Released from Hold"
         Case 8
            If IsConditional Then Return "Conditional Modified"
            If IsHeld Then Return "Held Modified"
            Return "Modified"
         Case 9
            If IsConditional Then Return "Conditional Discontinued for the Future"
            If IsHeld Then Return "Held Discontinued for the Future"
            Return "Discontinued for the Future"
         Case 10
            If IsConditional Then Return "Conditional Verified"
            If IsHeld Then Return "Held Verified"
            Return "Verified"
         Case 11
            If IsConditional Then Return "Conditional Modified And Verified"
            If IsHeld Then Return "Held Modified And Verified"
            Return "Modified And Verified"
         Case 12
            If IsConditional Then Return "Hold Conditional Cancelled"
            If IsHeld Then Return "Hold Held Cancelled"
            Return "Hold Cancelled"
         Case Else
            Return ""
      End Select
   End Function

   Sub ComputeLabelsSteve()
      Dim str As String = ""
      For i As Integer = 0 To 1000000
         For j As Integer = -1 To 13
            str = ComputeLabelSteve(j, False, False)
            str = ComputeLabelSteve(j, True, False)
            str = ComputeLabelSteve(j, False, True)
         Next
      Next
   End Sub

   Public Function ComputeLabelSteve(ByVal Action As Integer, ByVal IsHeld As Boolean, ByVal IsConditional As Boolean) As String
      Select Case Action
         Case 0
            Return ""
         Case 1
            If IsConditional Then
               Return "Conditional Cancelled"
            ElseIf IsHeld Then
               Return "Held Cancelled"
            Else
               Return "Cancelled"
            End If
         Case 2
            If IsConditional Then
               Return "Conditional Discontinued"
            ElseIf IsHeld Then
               Return "Held Discontinued"
            Else
               Return "Discontinued"
            End If
         Case 3
            If IsConditional Then
               Return "Conditional Suspended"
            ElseIf IsHeld Then
               Return "Held Suspended"
            Else
               Return "Suspended"
            End If
         Case 4
            If IsConditional Then
               Return "Conditional Unsuspended"
            ElseIf IsHeld Then
               Return "Held Unsuspended"
            Else
               Return "Unsuspended"
            End If
         Case 6
            If IsConditional Then
               Return "Conditional Collected"
            ElseIf IsHeld Then
               Return "Held Collected"
            Else
               Return "Collected"
            End If
         Case 7
            If IsConditional Then
               Return "Conditional Released from Hold"
            ElseIf IsHeld Then
               Return "Held Released from Hold"
            Else
               Return "Released from Hold"
            End If
         Case 8
            If IsConditional Then
               Return "Conditional Modified"
            ElseIf IsHeld Then
               Return "Held Modified"
            Else
               Return "Modified"
            End If
         Case 9
            If IsConditional Then
               Return "Conditional Discontinued for the Future"
            ElseIf IsHeld Then
               Return "Held Discontinued for the Future"
            Else
               Return "Discontinued for the Future"
            End If
         Case 10
            If IsConditional Then
               Return "Conditional Verified"
            ElseIf IsHeld Then
               Return "Held Verified"
            Else
               Return "Verified"
            End If
         Case 11
            If IsConditional Then
               Return "Conditional Modified And Verified"
            ElseIf IsHeld Then
               Return "Held Modified And Verified"
            Else
               Return "Modified And Verified"
            End If
         Case 12
            If IsConditional Then
               Return "Hold Conditional Cancelled"
            ElseIf IsHeld Then
               Return "Hold Held Cancelled"
            Else
               Return "Hold Cancelled"
            End If
         Case Else
            Return ""
      End Select
   End Function

   Sub ComputeLabelsChoose()
      Dim str As String = ""
      For i As Integer = 0 To 1000000
         For j As Integer = -1 To 13
            str = ComputeLabelChoose(j, False, False)
            str = ComputeLabelChoose(j, True, False)
            str = ComputeLabelChoose(j, False, True)
         Next
      Next
   End Sub

   Public Function ComputeLabelChoose(ByVal Action As Integer, ByVal IsHeld As Boolean, ByVal IsConditional As Boolean) As String
      Dim Status As String = ""

      Select Case Action
         Case 0, 5
            Return ""
         Case 1 To 11
            Status = Choose(Action, "Cancelled", "Discontinued", "Suspended", _
            "Unsuspended", "Collected", "Released from Hold", "Modified", _
            "Discontinued for the Future", "Verified", "Modified And Verified")
         Case 12
            If IsConditional Then
               Return "Hold Conditional Cancelled"
            ElseIf IsHeld Then
               Return "Hold Held Cancelled"
            Else
               Return "Hold Cancelled"
            End If
         Case Else
            Return ""
      End Select
      If IsConditional Then Return "Conditional " & Status
      If IsHeld Then Return "Held " & Status
      Return Status
   End Function

   Sub ComputeLabelsBigArray()
      OrderLabelsBigArray = New String() {"", "Cancelled", "Discontinued", "Suspended", "Unsuspended", "", "Collected", "Released from Hold", "Modified", "Discontinued for the Future", "Verified", "Modified And Verified", "Hold Cancelled", _
      "", "Conditional Cancelled", "Conditional Discontinued", "Conditional Suspended", "Conditional Unsuspended", "Conditional ", "Conditional Collected", "Conditional Released from Hold", "Conditional Modified", "Conditional Discontinued for the Future", "Conditional Verified", "Conditional Modified And Verified", "Hold  Cancelled", _
      "", "Held Cancelled", "Held Discontinued", "Held Suspended", "Held Unsuspended", "Held ", "Held Collected", "Held Released from Hold", "Held Modified", "Held Discontinued for the Future", "Held Verified", "Held Modified And Verified", "Hold  Cancelled"}

      Dim str As String = ""
      For i As Integer = 0 To 1000000
         For j As Integer = -1 To 13
            str = ComputeLabelChoose(j, False, False)
            str = ComputeLabelChoose(j, True, False)
            str = ComputeLabelChoose(j, False, True)
         Next
      Next
   End Sub

   Public Function ComputeLabelBigArray(ByVal Action As Integer, ByVal IsHeld As Boolean, ByVal IsConditional As Boolean) As String
      If Action < 0 OrElse Action >= 13 Then Return ""
      Return OrderLabelsBigArray(Action - IsConditional * 13 - (IsHeld AndAlso Not IsConditional) * 26)
   End Function
End Module

现在如果我犯了另一个错误,有人可以帮助找到它。

【讨论】:

  • 这些结果没有意义。我的意思是,这与我的测试完全不一致。一定有什么问题。您是在一个大型基准测试中运行每个函数,还是每次尝试都更改代码并重新编译?如果你把它作为一个长期的基准测试,你是否在每次测试之间重置了秒表?我的意思是……我现在很困惑。
  • 好的,大声笑...也许我又着迷了,但我只是从头开始编写了另一个基准来模仿您的基准,并用它更新了我的答案。这次我把整个事情都贴出来了。如果你运行它,我想知道你是否会得到和我一样的结果。
  • 你说得对。叹息超越一切。你看,我检查了我的代码,发现我没有遗漏任何东西。也就是说,我在循环结束时遗漏了一个小零,因此 Initial Post 只运行了 100,000 次而不是 1,000,000 次。所以所有的数字都是对的,除了第一个,它应该大十倍。对此我深表歉意。
  • 瞧,我还犯了另一个错误,假设某些东西是等效的:If A Then Return 'A' / If B Then Return 'B'If A Then / Return 'A' / ElseIf B Then / Return 'B' / End If。这些是不等价的,第二种方式更快。我在测试中更改了您建议的代码。另一个教训。再次更新号码...
【解决方案5】:

Steve Wortham 已经说过最重要的事情:函数中唯一低效的部分是字符串连接。如果您真的需要该函数快速,请忽略源代码长度并显式扩展每个案例,这样您就可以避免连接字符串。

我想补充一点:使用数组不会帮助您优化函数。 .NET 数组不是 C 数组,它们是必须构造、填充数据和销毁的复杂对象。

【讨论】:

  • 这个想法是,与构建数组并杀死它一样昂贵,这只会在实例化时完成一次(SSRS 报告的代码部分是一个静态类)并由287 次调用从数组中提取字符串的函数的速度。
  • 我不同意这一点。在我的帖子中,我在 Emtucifor 描述的方法中使用了数组,并且执行时间比 Steve Wortham 的帖子要短。
  • 事实证明,从长远来看,我太仓促而无法投票给这篇文章。显然,这实际上是不正确的,尽管我很感激参与。
【解决方案6】:

对这个版本有什么想法吗?

Public Shared Function ComputeLabel(ByVal Action As Integer, ByVal IsHeld As Boolean, ByVal IsConditional As Boolean) As String
   Dim Status As String = ""

   Select Case Action
      Case 0
         Return ""
      Case 1
         Status = "Cancelled"
      Case 2
         Status = "Discontinued"
      Case 3
         Status = "Suspended"
      Case 4
         Status = "Unsuspended"
      Case 6
         Status = "Collected"
      Case 7
         Status = "Released from Hold"
      Case 8
         Status = "Modified"
      Case 9
         Status = "Discontinued for the Future"
      Case 10
         Status = "Verified"
      Case 11
         Status = "Modified And Verified"
      Case 12
         If IsConditional Then Return "Hold Conditional Cancelled"
         If IsHeld Then Return "Hold Held Cancelled"
         Return "Hold Cancelled"
      Case Else
         Return ""
   End Select
   If IsConditional Then Return "Conditional " & Status
   If IsHeld Then Return "Held " & Status
   Return Status
End Function

还是这个?

Public Shared Function ComputeLabel(ByVal Action As Integer, ByVal IsHeld As Boolean, ByVal IsConditional As Boolean) As String
   Dim Status As String = ""

   Select Case Action
      Case 0, 5
         Return ""
      Case 1 To 11
         Status = Choose(Action, "Cancelled", "Discontinued", "Suspended", _
         "Unsuspended", "Collected", "Released from Hold", "Modified", _
         "Discontinued for the Future", "Verified", "Modified And Verified")
      Case 12
         If IsConditional Then
            Return "Hold Conditional Cancelled"
         ElseIf IsHeld Then
            Return "Hold Held Cancelled"
         Else
            Return "Hold Cancelled"
         End If
      Case Else
         Return ""
   End Select
   If IsConditional Then Return "Conditional " & Status
   If IsHeld Then Return "Held " & Status
   Return Status
End Function

我怀疑选择功能可能真的很慢...

而且我猜原始函数对于维护代码的人来说可能仍然比其他任何选项都更清晰。叹息。

【讨论】:

  • 我认为您的第二个 sn-p 在可读性或速度方面对您没有太大帮助。但我确实喜欢第一个代码 sn-p。它应该稍微快一点,因为您说案例 0 是最常见的,并且您已经移动了代码以更好地优化它。然而它仍然是可以理解的。
  • 顺便说一句,Choose 功能真的很慢。
猜你喜欢
  • 2013-05-20
  • 1970-01-01
  • 1970-01-01
  • 2019-04-29
  • 1970-01-01
  • 2017-05-20
  • 2016-03-13
  • 2019-09-09
  • 1970-01-01
相关资源
最近更新 更多