Is Try/Catch ever LESS expensive than a hash lookup?

强颜欢笑 提交于 2019-12-10 15:55:26

问题


I'm aware that exception trapping can be expensive, but I'm wondering if there are cases when it's actually less expensive than a lookup?

For example, if I have a large dictionary, I could either test for the existence of a key:

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

Or, I could catch an exception:

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

Is exception trapping always more expensive than lookups like the above, or is it less so in some circumstances?


回答1:


The thing about dictionary lookups is that they happen in constant or near-constant time. It takes your computer about the same amount of time whether your dictionary holds one item or one million items. I bring this up because you're worried about making two lookups in a large dictionary, and reality is that it's not much different from making two lookups in a small dictionary. As a side note, one of the implications here is that dictionaries are not always the best choice for small collections, though I normally find the extra clarity still outweighs any performance issues for those small collections.

One of the things that determines just how fast a dictionary can make it's lookups is how long it takes to generate a hash value for a particular object. Some objects can do this much faster than others. That means the answer here depends on the kind of object in your dictionary. Therefore, the only way to know for sure is to build a version that tests each method a few hundred thousand times to find out which completes the set faster.

Another factor to keep in mind here is that it's mainly just the Catch block that is slow with exception handling, and so you'll want to look for the right combination of lookup hits and misses that reasonably matches what you'd expect in production. For this reason, you can't find a general guideline here, or if you do it's likely to be wrong. If you only rarely have a miss, then I would expect the exception handler to do much better (and, by virtue of the a miss being somewhat, well, exceptional, it would also be the right solution). If you miss more often, I might prefer a different approach

And while we're at it, let's not forget about Dictionary.TryGetValue()




回答2:


I tested performance of ContainsKey vs TryCatch, here are the results:

With debugger attached:

Without debugger attached:

Tested on Release build of a Console application with just the Sub Main and below code. ContainsKey is ~37000 times faster with debugger and still 355 times faster without debugger attached, so even if you do two lookups, it would not be as bad as if you needed to catch an extra exception. This is assuming you are looking for missing keys quite often.

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.")



回答3:


If you are trying to find an item in a data structure of some kind which is not easily searched (e.g. finding an item containing the word "flabbergasted" in an unindexed string array of 100K items, then yes, letting it throw the exception would be faster because you'd only be doing the look-up once. If you check if the item exists first, then get the item, you are doing the look-up twice. However, in your example, where you are looking up an item in a dictionary (hash table), it should be very quick, so doing the lookup twice would likely be faster than letting it fail, but it's hard to say without testing it. It all depends how quickly the hash value for the object can be calculated and how many items in the list share the same hash value.

As others have suggested, in the case of the Dictionary, the TryGetValue would provide the best of both methods. Other list types offer similar functionality.



来源:https://stackoverflow.com/questions/13689144/is-try-catch-ever-less-expensive-than-a-hash-lookup

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!