7

我有一个巨大的数据表,我需要遍历每一行并验证一个特定的值。

哪种方法给我更多的性能,IF ELSE 或 SELECT CASE 的结构?(我专注于为我提供最佳性能的方法)

否则(方法 #1)

For Each vRow In vDTtemp.Rows
    If vRow("Item") = "Time" Then
        vRow("Result") = "000"
    ElseIf vRow("Item") = "DateTime" Then
        vRow("Result") = "001"
    ElseIf vRow("Item") = "String" Then
        vRow("Result") = "002"
    Else
        vRow("Result") = "N/A"
    End If
Next

选择案例(方法#2)

For Each vRow In vDTtemp.Rows
    Select Case vRow("Item")
        Case "Time"
            vRow("Result") = "000"
        Case "DateTime"
            vRow("Result") = "001"
        Case "String"
            vRow("Result") = "002"
        Case Else
            vRow("Result") = "N/A"
    End Select
Next
4

4 回答 4

6

没有区别,两种代码样式都会生成完全相同的 IL。通过在已编译的程序集上运行 ildasm.exe 工具可以看到一些内容。

通常,VB.NET 编译器确实会努力优化 Select 语句。当它使用简单的值类型作为选择器和平凡的 Case 语句时,这将起作用。生成的代码将使用专用的 IL 指令Opcodes.Switch。它将被编译为使用查找表的机器代码。非常快。

但是,当您使用字符串表达式作为选择器时,这不起作用。为那个创建一个查找表需要相当于一个代表字典。这影响太大了,编译器只能将每个 case 语句转换为等效的 If 语句。但是,您可以通过在代码中创建此 Dictionary 来轻松优化它,因为字典键和值只是简单的字符串,因此很容易做到。你没有足够的箱子,而且琴弦太短,无法让这主要得到回报,尽管值得一试。它当然可以压缩你的代码。

于 2013-02-28T21:04:22.030 回答
6

在过去的几天里,我花了很多时间来解决同样的问题,并且找到了一种比其他方法快得多的方法。我也发现在字符串变量上使用 Select Case 等同于一系列 If/Else If 语句,而且两者都慢得令人失望。

但是,以下技术效果很好,并且将时间减少了 50% 以上。而不是原始代码:

For Each vRow In vDTtemp.Rows
    Select Case vRow("Item")
        Case "Time"
            vRow("Result") = "000"
        Case "DateTime"
            vRow("Result") = "001"
        Case "String"
            vRow("Result") = "002"
        Case Else
            vRow("Result") = "N/A"
    End Select
Next

更改它以打开一个简单的布尔值,并使用 String.Equals 方法,如下所示:

For Each vRow In vDTtemp.Rows
    'Read out the row value so we only need to access the datarow once
    rowValue = vRow("Item")
    'Which of these statements is true?
    Select Case True
        Case rowValue.Equals("Time")
            vRow("Result") = "000"
        Case rowValue.Equals("DateTime")
            vRow("Result") = "001"
        Case rowValue.Equals("String")
            vRow("Result") = "002"
        Case Else
            vRow("Result") = "N/A"
    End Select
Next

通过以这种方式接近它,我已经有了显着的改进,在一种情况下,我的代码从 100,000 次迭代循环中的 1.3 秒减少到 0.5 秒。如果这是在一个真正经常被称为时间关键的代码部分,那可能会产生很大的不同。

然而,正如在下面的评论中指出的那样,这会执行字符串的“序数”比较,如果使用非英语语言环境,这可能不会导致预期的行为(请参阅评论以获取示例)。

亚当。

于 2013-11-20T14:18:22.263 回答
5

好的......这篇文章很久以前了,但现在我正在搜索相同的问题,我可以为此添加新的优化。现在我选择使用选择案例,以便更具可读性。另一方面,当“Dim”在 for-next 循环中时,性能会下降很多。

     For Each vRow In vDTtemp.Rows
------->  Dim rowItem = vRow("Item")
        If rowItem = "Time" Then
            vRow("Result") = "000"
        ElseIf rowItem = "DateTime" Then
            vRow("Result") = "001"
        ElseIf rowItem = "String" Then
            vRow("Result") = "002"
        Else
            vRow("Result") = "N/A"
        End If
    Next

即使您想使用 if-then 结构,当 dim 处于 oitside 时也会快得多:

------->     Dim rowItem as string
             For Each vRow In vDTtemp.Rows
------->            rowitem= vRow("Item")
                If rowItem = "Time" Then
                    vRow("Result") = "000"
                ElseIf rowItem = "DateTime" Then
                    vRow("Result") = "001"
                ElseIf rowItem = "String" Then
                    vRow("Result") = "002"
                Else
                    vRow("Result") = "N/A"
                End If
            Next

我希望这对更多人有帮助;)

于 2016-02-01T15:47:03.993 回答
2

如果您真的发现这是您的性能瓶颈,您可以尝试修改 If..Then 子句,如下所示仅访问索引器一次:

For Each vRow In vDTtemp.Rows
    Dim rowItem = vRow("Item")
    If rowItem = "Time" Then
        vRow("Result") = "000"
    ElseIf rowItem = "DateTime" Then
        vRow("Result") = "001"
    ElseIf rowItem = "String" Then
        vRow("Result") = "002"
    Else
        vRow("Result") = "N/A"
    End If
Next

话虽如此,我怀疑这些都是过度优化的案例。编译器应该在这里做最好的事情。如果您从一个较长的 Select Case 中检查 IL,您可能会发现它在“goto”的封面下使用了一串 If..then 子句来转义其余子句。您最好的选择是获得最可维护的代码,因为您可能获得的性能优势将被您在 if..then 和 select case 之间看到的最小提升所抵消。

于 2013-02-28T21:00:53.837 回答