Try / Catch是否比哈希查找更昂贵?

时间:2012-12-03 18:09:10

标签: vb.net exception-handling

我知道异常捕获可能很昂贵,但是我想知道是否存在实际上比查找更便宜的情况?

例如,如果我有一个大字典,我可以测试是否存在密钥:

If MyDictionary.ContainsKey(MyKey) Then _
  MyValue = MyDictionary(MyKey) ' This is 2 lookups just to get the value.

或者,我可能会遇到异常:

Try
  MyValue = MyDictionary(MyKey) ' Only doing 1 lookup now.
Catch(e As Exception)
  ' Didn't find it.
End Try

异常捕获是否总是比上面的查找更昂贵,或者在某些情况下是否更少?

3 个答案:

答案 0 :(得分:5)

关于字典查找的事情是它们在恒定或接近恒定的时间内发生。无论您的词典是包含一个项目还是一百万个项目,您的计算机都需要大约相同的时间。我提出这个问题是因为你担心在大字典中进行两次查找,而现实情况是它与在一个小字典中进行两次查找没什么不同。作为旁注,其中一个含义是字典并不总是小集合的最佳选择,尽管我通常发现额外的清晰度仍然超过这些小集合的任何性能问题。

确定字典查找速度的速度之一是为特定对象生成hash值需要多长时间。有些对象比其他对象更快。这意味着这里的答案取决于词典中的对象类型。因此,唯一可以确定的方法是构建一个测试每个方法几十万次的版本,以找出更快完成集合的方法。

这里要记住的另一个因素是它主要只是Catch块在异常处理时很慢,因此你需要寻找合理匹配你期望的查找命中和未命中的正确组合在生产中。因此,您无法在此找到一般指南,或者如果您这样做可能会出错。如果你很少有一个错过,那么我希望异常处理程序做得更好(并且,由于错过了一些,很好,特殊,它也将是正确的解决方案) 。如果你经常错过,我可能更喜欢不同的方法

虽然我们正在努力,但我们不要忘记Dictionary.TryGetValue()

答案 1 :(得分:1)

我测试了ContainsKeyTryCatch的效果,结果如下:

附带调试器:

enter image description here

没有附带调试器:

enter image description here

仅使用Sub Main及以下代码在控制台应用程序的发布版本上进行测试。 ContainsKey使用调试器的速度提高了约37000倍,并且在没有附加调试器的情况下仍然快了355倍,所以即使你进行两次查找,也不会像需要捕获额外的异常那样糟糕。这是假设您经常寻找丢失的密钥。

Dim dict As New Dictionary(Of String, Integer)
With dict
  .Add("One", 1)
  .Add("Two", 2)
  .Add("Three", 3)
  .Add("Four", 4)
  .Add("Five", 5)
  .Add("Six", 6)
  .Add("Seven", 7)
  .Add("Eight", 8)
  .Add("Nine", 9)
  .Add("Ten", 10)
End With

Dim stw As New Stopwatch
Dim iterationCount As Long = 0
Do
  stw.Start()
  If Not dict.ContainsKey("non-existing key") Then 'always true
    stw.Stop()
    iterationCount += 1
  End If
  If stw.ElapsedMilliseconds > 5000 Then Exit Do
Loop

Dim stw2 As New Stopwatch
Dim iterationCount2 As Long = 0
Do
  Try
    stw2.Start()
    Dim value As Integer = dict("non-existing key") 'always throws exception
  Catch ex As Exception
    stw2.Stop()
    iterationCount2 += 1
  End Try
  If stw2.ElapsedMilliseconds > 5000 Then Exit Do
Loop

MsgBox("ContainsKey: " & iterationCount / 5 & " per second, TryCatch: " & iterationCount2 / 5 & " per second.")

答案 2 :(得分:0)

如果你试图在某种数据结构中找到一个不容易搜索的项目(例如在一个100K项目的无索引字符串数组中找到包含单词“flabbergasted”的项目,那么是的,让它抛出异常会更快,因为你只会进行一次查找。如果你先检查项目是否存在,那么得到项目,你正在进行两次查找。但是,在你的例子中,你正在寻找在字典(哈希表)中的一个项目,它应该非常快,所以进行两次查找可能比让它失败更快,但是如果没有测试就很难说。这一切都取决于哈希值的快速有多快可以计算对象以及列表中有多少项共享相同的哈希值。

正如其他人所建议的那样,对于DictionaryTryGetValue将提供两种方法中的最佳方法。其他列表类型提供类似的功能。