4

例外トラップが高価になる可能性があることは承知していますが、ルックアップよりも実際に安価なケースがあるかどうか疑問に思っています。

たとえば、大きな辞書がある場合、キーの存在をテストできます。

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

例外トラップは、上記のようなルックアップよりも常にコストがかかりますか、それとも状況によってはそれほど高くありませんか?

4

3 に答える 3

5

ディクショナリの検索に関する問題は、それらが一定またはほぼ一定の時間で発生することです。辞書に含まれる項目が 1 つであろうと 100 万項目であろうと、コンピューターにかかる時間はほぼ同じです。これを取り上げるのは、大きな辞書で 2 回の検索を行うことを心配しているからです。実際には、小さな辞書で 2 回の検索を行うことと大差ありません。補足として、ここでの含意の 1 つは、小さなコレクションには辞書が常に最適な選択であるとは限らないということです。

ディクショナリの検索速度を決定する要因の 1 つは、特定のオブジェクトのハッシュ値を生成するのにかかる時間です。一部のオブジェクトは、他のオブジェクトよりもはるかに高速にこれを実行できます。つまり、ここでの答えは、辞書内のオブジェクトの種類によって異なります。したがって、確実に知る唯一の方法は、各メソッドを数十万回テストして、セットをより速く完了するバージョンを見つけることです。

ここで留意すべきもう 1 つの要因は、例外処理で遅いのは主に Catch ブロックだけであるため、本番環境で期待するものと合理的に一致するルックアップ ヒットとミスの適切な組み合わせを探す必要があるということです。このため、ここでは一般的なガイドラインを見つけることができません。または、そうすると間違っている可能性があります。ミスがめったにない場合は、例外ハンドラーがはるかにうまく機能することを期待します(そして、ミスが多少、まあ、例外的であるため、それは正しい解決策でもあります)。あなたがもっと頻繁に逃すなら、私は別のアプローチを好むかもしれません

そして、私たちがそれに取り組んでいる間、忘れないようにしましょうDictionary.TryGetValue()

于 2012-12-03T18:19:07.173 に答える
1

ContainsKeyvsのパフォーマンスをテストしましTryCatchた。結果は次のとおりです。

デバッガーが接続されている場合:

ここに画像の説明を入力

デバッガーが接続されていない場合:

ここに画像の説明を入力

Sub Main以下のコードのみを使用して、コンソール アプリケーションのリリース ビルドでテスト済みです。ContainsKeyデバッガーを使用すると 37000 倍速くなり、デバッガーが接続されていない場合でも 355 倍速くなります。したがって、2 回ルックアップを行っても、追加の例外をキャッチする必要がある場合ほど悪くはありません。これは、紛失したキーを頻繁に探していることを前提としています。

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.")
于 2012-12-03T18:44:25.350 に答える
0

簡単に検索できないある種のデータ構造でアイテムを見つけようとしている場合 (たとえば、100K アイテムのインデックスのない文字列配列で "flabbergasted" という単語を含むアイテムを見つける場合、はい、例外をスローさせます。ルックアップを 1 回だけ行うため、より高速です。最初にアイテムが存在するかどうかを確認してからアイテムを取得すると、ルックアップを 2 回実行することになります。ただし、この例では、アイテムをルックアップする場所でディクショナリ (ハッシュ テーブル) では非常に高速である必要があるため、ルックアップを 2 回行うと、失敗するよりも高速になる可能性がありますが、テストせずに言うのは難しいです. オブジェクトのハッシュ値がどれだけ速くなるかによって異なります.計算され、リスト内で同じハッシュ値を共有するアイテムの数。

他の人が示唆しているように、 の場合、DictionaryTryGetValue両方の方法の最良のものを提供します。他の種類のリストでも同様の機能が提供されます。

于 2012-12-03T18:22:25.183 に答える