【问题标题】:Speed impact of On Error Resume NextOn Error Resume Next 对速度的影响
【发布时间】:2014-02-20 08:15:49
【问题描述】:

鉴于vbscript 不像vba 那样具有On Error Goto MyLabel 类型的语法,我正在考虑使用以下方法来处理错误:

On Error Resume Next

'Do some stuff

If Err.Number <> 0 Then
    Err.Clear
    'Handle the error
End If

'Do some more stuff

If Err.Number <> 0 Then
    Err.Clear
    'Handle the error
End If

'...

我的问题是:这种技术会对速度产生什么影响?

另外,我想知道是否有更好的方法可以在vbscript 中构建一些错误处理

【问题讨论】:

    标签: vbscript


    【解决方案1】:
    1. 比较正确和错误实现的速度是没有意义的。如果您的脚本在没有错误处理的情况下无法满足其规范,并且在使用 OERN 时速度变慢,则您必须选择另一种语言。
    2. 由于 OERN 隐藏错误,其范围应尽可能小。您的示例代码闻起来像在全球范围内使用 OERN - 这是一个非常糟糕的主意。另外:每次有风险的操作和对应的 Err.Number 检查后,都需要 Err.Clear 或“On Error GoTo 0”。
    3. 在其他语言中(例如 Python)"it's easier to ask forgiveness than permission";由于 VBScript 错误处理的糟糕性质,在大多数情况下,您应该“三思而后行”,并且仅在绝对不可避免时才使用 OERN(例如,检查注册表项是否存在,处理可能出现故障的外部资源)。

    本地错误处理的成语:

    Dim gaErr ' global error array
    ...
    Sub SomeSub()
        ...
        OERN
        risky op
        gaErr = Array(Err.Number, Err.Description, ...)
        OEG0
        If gaErr(0) Then
           handle error
        ...
    End Sub
    

    如果您的规范要求进行全局错误处理:

    Dim gaErr
    OERN
    ret = main()
    gaErr = Array(...)
    OEG0
    If gaErr(0) Then
       some fatal/not locally handled error occured somewhere in your script
       handle it gracefully
    Else
       If ret is bad Then
          deal with this
       Else
          ask for more money
       End If
    End If
    WScript.Quit good/bad
    
    Function main()
      main = ...
    End Function
    

    更新评论:

    为什么全球 OERN 是邪恶的?考虑:

    OERN
    (1) Process/change important data
    (2) Delete original data - if (1) failed you just destroyed the base of your business
    
    OERN
    (1) Process/change important data
    (2) If Err.Nunber Then Backup(database, destinatiom)
    (3) Continue although the Backup didn't take place, because at least three error were hidden
    

    顺便说一句:您添加 Err.Clear 的位置有误 - 您可以处理错误之前丢失了错误信息。

    更新评论 II:

    考虑这个演示脚本:

    ' dgeh.vbs - demo global error handling
    
    Option Explicit
    
    ' globals
    Dim gWAN : Set gWAN = WScript.Arguments.Named
    Dim gaErr
    
    Dim iRet
    ' top-level/global OERN starts here (errors before will abort mercylessly)
    On Error Resume Next
     iRet  = main() ' not more than two statements!
     gaErr = Array(Err.Number, Err.Description, Err.Source)
    On Error GoTo 0
    If gaErr(0) Then
       WScript.Echo "Fatal Error:", Join(gaErr, " * ")
       iRet = 1 ' or choose a better number
    Else
       If iRet Then
          WScript.Echo "need one of /good, /bad, or /fatal, Mr. User!"
       Else
          WScript.Echo "all's well"
       End If
    End If
    WScript.Quit iRet
    
    Function main()
      main = 2
      If gWAN.Count = 1 And (gWAN.Exists("good") Or gWAN.Exists("bad") Or gWAN.Exists("fatal")) Then
         readTheDocs
         main = 0
      End If
    End Function
    
    Sub readTheDocs()
        WScript.Echo "read Microsoft's Docs"
        If gWAN.Exists("fatal") Then
           caTastrophy
        Else
           trySomethingRisky
        End If
    End Sub
    
    Sub trySomethingRisky()
      Dim n
      If gWAN.Exists("bad") Then n = 1 / 0
      WScript.Echo "but be skeptical of the text and your interpretation"
    End Sub
    
    Sub caTastrophy()
      On Error Resume Next ' simulating the evil global OERN and not checking *each* statement
         WScript.Echo "saving the world"
         saveTheWorld
         WScript.Echo "deleting the now obsolete original"
      On Error GoTo 0
    End Sub
    

    输出

    cscript dgeh.vbs /fatal
    read Microsoft's Docs
    saving the world
    deleting the now obsolete original
    all's well
    echo %ERRORLEVEL%
    0
    

    由于没有 Sub saveTheWorld,您只是将错误处理、VBScript 和所有其他内容都过时了。你甚至不能保证永远不再使用邪恶的全局 OERN,因为你——以及那些习惯性地使用它的脚本编写人员(从而证明他们是为他们的笑话而不是他们的代码获得报酬的)——已经消失了。让我们希望调用过程不会将 ERRORLEVEL 值作为进一步删除的许可。

    输出

    cscript dgeh.vbs
    need one of /good, /bad, or /fatal, Mr. User!
    echo %ERRORLEVEL%
    2
    
    cscript dgeh.vbs /nix
    need one of /good, /bad, or /fatal, Mr. User!
    
    cscript dgeh.vbs /fatal /bad
    need one of /good, /bad, or /fatal, Mr. User!
    

    展示“先看再跳”策略。

    良好案例的输出:

    cscript dgeh.vbs /good
    read Microsoft's Docs
    but be skeptical of the text and your interpretation
    all's well
    echo %ERRORLEVEL%
    0
    

    两条消息都显示了(理所当然)。

    现在完全不同了:

    cscript dgeh.vbs /bad
    read Microsoft's Docs
    Fatal Error: 11 * Division by zero * Microsoft VBScript runtime error
    echo %ERRORLEVEL%
    1
    

    请标记第二条消息的缺失。除以零将导致在活动 OERN 范围内执行下一行(保存在 gaErr 中)并且 not 继续盲目/盲目地。然后检查有风险的操作(执行 main() 及其所有子项所做的操作)(通过 gaErr 代理)。这符合“在 OERN 范围内不超过两行(风险操作和保存错误信息)”的规则。

    为这种全局错误处理付出的代价:您丢失了行号信息 - 优雅地处理错误变得更加困难。

    但是由于您的脚本中只有一个 OERN(从现在开始您的程序中不会有 Sub caTastrophy()),您可以在开发和调试期间将其注释掉。

    注释掉 OERN 的输出:

    cscript dgeh.vbs /bad
    read Microsoft's Docs
    E:\trials\SoTrials\answers\21901890\vbs\dgeh.vbs(46, 30) Microsoft VBScript runtime error: Division by zero
    

    【讨论】:

    • 感谢您的回答。我已经编辑了这个问题,以表明我将如何做Err.Clear 部分。该应用程序在 Oracle HFM 中,所以我只能使用 VBScript。我确实打算在全球范围内使用 OERN,因为我们正在谈论 10000+ 行脚本,并且在环境中错误处理非常困难......它只会中止,找出问题所在的唯一方法是写信给日志文件,只有在不使用 OERN 的情况下,错误发生后才能写入日志。你能解释一下为什么在全球范围内使用 OERN 会不好吗?
    • 不错的答案,@Ekkehard,但是:dox 说“当调用另一个过程时,OERN 语句变得不活动,因此如果您希望在该例程中进行内联错误处理,则应该在每个调用的例程中执行 OERN 语句” .这是否意味着提议的全局错误处理是不切实际的,因为全局执行 OEGN 不会启用全局错误处理——调用函数将需要函数(及其所有被调用者!)也执行 OEGN,对吗?这是我在您的回答中缺少的唯一方面,尤其是因为它是反对尝试在全球范围内使用 OERN 的杀手锏。
    【解决方案2】:

    当我在 Vbscript 中使用错误处理时,我发现它没有性能问题。但是在我的程序中,它通常会做一些非常简单的事情,比如将“失败”语句输出到日志文件然后wscript.quit,所以我从来没有发现它会降低系统性能。在您给出的示例中,通常在您检查错误的最后一个End If 之后添加On Error Goto 0。这可能会导致错误无法清除,因此当您下次执行错误检查时,它仍然错误地存储旧的错误值。

    【讨论】:

      猜你喜欢
      • 2017-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-13
      • 2011-06-17
      • 2017-05-09
      • 1970-01-01
      相关资源
      最近更新 更多