VB.NET 如何提供最佳性能“选择案例”或 IF... ELSEIF ... ELSE... END IF

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15144104/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 16:42:40  来源:igfitidea点击:

VB.NET How give best performance "Select case" or IF... ELSEIF ... ELSE... END IF

vb.netperformanceif-statementswitch-statementcycle

提问by MiBol

I have a huge DataTable, and I need go by each row and validate an specific value.

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

Which method give me more performance, an structure of IF ELSE or SELECT CASE? (I'm focused in the method that offer me the best performance)

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

IF ELSE (METHOD #1)

如果其他(方法#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

SELECT CASE (METHOD #2)

选择案例(方法#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

采纳答案by Adam Dawes

I've spent quite a lot of time working on this same problem over the last couple of days and have found one approach which is much faster than the others. I too found that using Select Case on a string variable was equivalent to a series of If/Else If statements, and both were disappointingly slow.

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

However the following technique has worked very well, and reduced the amount of time by over 50%. Instead of the original code:

但是,以下技术效果很好,将时间减少了 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

Change it around to switch on a simple Boolean, and use the String.Equals method, like this:

更改它以打开一个简单的布尔值,并使用 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

I've had significant improvements by approaching it in this way, in one case reducing my code from 1.3 seconds over a 100,000 iteration loop to 0.5 seconds. If this is in a really frequently-called time-critical section of code, that can make a big difference.

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

As pointed out in the comments below however, this performs an "Ordinal" comparison of strings, which may not result in the expected behaviour if non-English locales are being used (see the comments for examples).

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

Adam.

亚当。

回答by Hans Passant

It makes no difference, both code styles generate the exact same IL. Something you can see by running the ildasm.exe tool on your compiled assembly.

这没什么区别,两种代码风格都生成完全相同的 IL。通过在编译的程序集上运行 ildasm.exe 工具,您可以看到一些东西。

In general, the VB.NET compiler doesmake an effort to optimize a Select statement. That will work when it uses a simple value type as the selector and trivial Case statements. The generated code will use a dedicated IL instruction, Opcodes.Switch. Which will be compiled to machine code that uses a lookup table. Very fast.

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

That however doesn't work when you use a string expression as the selector. Making a lookup table for that one would require the equivalent of a dictionary of delegates. That's too impactful, the compiler cannot do anything but convert each case statement to the equivalent of an If statement. You can however optimize it yourself easily by creating this Dictionary in your code, easy to do since the dictionary key and value are just simple strings. You don't have enough cases and the strings are too short to make this pay off majorly, although it is worth a try. It certainly can compact your code.

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

回答by Ivan Font

Ok... it was long time ago for this post, but now i was searching the same question and i can add new optimization for this. For now i've choosed to use the select case, for be more readable. In the other hand, the performance decreases a lot when a "Dim" is inside a for-next loop.

好吧……这篇文章很久以前了,但现在我正在搜索同样的问题,我可以为此添加新的优化。现在我选择使用 select 案例,以提高可读性。另一方面,当“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

It's a lot faster when dim is oitside even if you want to use the if-then structure:

即使您想使用 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

I hope this be helpful for someone more ;)

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

回答by Jim Wooley

If you really find this is your bottleneck in performance, you could try modifying the If..Then clause as follows to only access the indexer once:

如果你真的发现这是你的性能瓶颈,你可以尝试修改 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

That being said, I suspect each of these is a case of over optimizing. The compiler should to the best thing here. If you check the IL from a long Select Case, you may find that it uses a string of If..then clauses under the covers with "goto" to escape the rest of the clauses. Your best option here is to get the most maintainable code as the performance benefits you may gain will be offset by the minimal boost you may see between if..then and select case.

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