25

Python での例外処理について誰かと短い議論を交わした後 (キュー オブジェクトの処理に端を発して)、私はそれを捨てようと思いました...

方法 1:

import Queue

q = Queue.Queue()

try:
    task=q.get(False)
    #Opt 1: Handle task here and call q.task_done()
except Queue.Empty:
    #Handle empty queue here
    pass

#Opt2: Handle task here and call q.task_done()

方法 2:

import Queue

q = Queue.Queue()

if q.empty():
    #Handle empty queue here
else:
    task = q.get()
    #Handle task here
    q.task_done()

引数の 1 つは、キューが空であることはエラーではないため、方法 1 は間違っているため、Queue.Empty 例外を使用して処理すべきではないというものです。さらに、この方法でコーディングすると、タスク処理部分が潜在的に大きくなる可能性があると考えると、デバッグがより困難になる可能性があります。

もう 1 つの議論は、Python ではどちらの方法も受け入れられ、タスク処理が大きい場合、try/except の外でタスクを処理するとデバッグに役立つ可能性があるということです。

意見?

更新: 回答 1 の後のもう少しの情報.... 議論は、方法 1 がマルチスレッド コードで使用された後に開始されました。その場合、コードは (threading.Lock オブジェクトから) ロックを取得し、タスクが返されるか Queue.Empty がスローされるとロックを解放します。

更新 2: キュー オブジェクトがスレッド セーフであることは、私たち二人とも知りませんでした。try/except が最適なようです。

4

3 に答える 3

51

方法 2 は、1 段階で実行できる操作を 2 段階で実行しているため、間違っています。方法 2 では、キューが空かどうかを確認し、後で (すぐに、しかしまだ後で)、アイテムを取得しようとします。キューから項目をプルする 2 つのスレッドがある場合はどうなるでしょうか。get() は、空のキューで失敗する可能性があります。キューが空であることを確認した後で、アイテムがキューに追加された場合はどうなりますか? これらは、並行コードにバグが忍び寄る小さな機会のようなものです。

ワンステップで実行してください。これははるかに優れた選択です。

import Queue

q = Queue.Queue()

try:
    task = q.get(False)
except Queue.Empty:
    # Handle empty queue here
    pass
else:
    # Handle task here and call q.task_done()

「例外はエラーでなければならない」にとらわれないでください。例外は単なる別の通信チャネルです。使用してください。ここで「else」句を使用して、例外句の範囲を狭めます。

于 2012-06-28T15:17:50.360 に答える
6

これがマルチスレッド/マルチプロセスコードである場合(とにかくキューを使用する正当な理由であるため)、間違いなく方法1です。q.empty()呼び出しと呼び出しの間にq.get()、JackofHeartsがタルトを盗んだ可能性があります。

于 2012-06-28T15:04:35.867 に答える
5

引数の 1 つは、キューが空であることはエラーではないため、方法 1 は間違っているため、Queue.Empty 例外を使用して処理すべきではないというものです。

例外は必ずしも「エラー」ではなく、一般的なフロー制御メカニズムであり、実際にいくつかのケース (SysExit、StopIteration など) でそのように使用されます。

ここでの良い質問は次のとおりです。最も一般的なケースは、空または空でないキューです。確かにわからない場合は、AskBeforeYouLeap を使用することをお勧めします。おそらく、はるかに安いからです。

于 2012-06-28T15:11:15.603 に答える