2016-11-30 12 views
1

のPython 3.xのロックはグローバルとして宣言する必要がありますか?

import threading 

lock = threading.Lock() 
counter = 0 

def update_counter(): 
    global counter 

    lock.acquire() 
    counter += 1 
    lock.release() 

# starts threads, target update_counter 

んが同様にグローバルでなければならないロック?そうでない場合、ローカルロックが定義されていないため、どのようにエラーは発生しませんか?

+0

試用中にエラーが発生しましたか? – Evert

+0

サイドノート: 'acquire'と' release'を手動で呼び出さないでください。可能であれば、 'with'ステートメントを使用してください。それは例外的に安全であり、 'acquire'と' release'呼び出しが適切に一致するのを忘れる可能性を避けます。 – ShadowRanger

答えて

1

直接質問に答えるために、あなただけlock上のメソッドを呼び出しているのに対し、あなたは(counter += 1で)counterに再割り当てされているので、counterニーズがgloballockを宣言するという理由があるものではありません。変数への参照については、ローカル変数が存在しない場合、Pythonはマッチするものが見つかるまで囲みスコープを調べます。この場合、グローバルスコープ内で検出されます。変数への代入の場合、Pythonは明示的に宣言されていない限り(globalまたはnonlocal)変数がローカルであるとみなします。

0

ロックは、いくつかのリソースを保護し、一般的にリソースと同じスコープされている、ありがとうございました。あなたのケースでは、ロックがグローバルでなければならないようにグローバルカウンタを保護しています。リソースにアクセスするすべてのスレッドは、同じロックを使用する必要があります。そのため、関数自体にプライベートロックを作成することはできません。他のスレッドはそれを見ません。

一部のアプリケーションでは、すべての共有リソースを保護するために単一のロックを使用します(コース単位のロック)。しかし、データでロックを保持することもできます(ファイングレインロック)。ファイングレイン・ロックの例がある:

class MyCounter: 

    def __init__(self): 
     self.lock = threading.Lock() 
     self.value = 0 

    def increment(self): 
     with self.lock: 
      self.value += 1 

すぐ、MyCounterの各インスタンスがロックを有し、独立して実行されます。

+0

これはpythonicと思われません – df86

+0

pythonicと思われないものはありますか?あなたの例では、保護しているリソースがグローバルなので、 'lock'はあなたが書いたのと同じようにグローバルでなければなりません。リソースを使用するすべてのコードは、ロックが機能するためには1つのロックを取得する必要があります。 – tdelaney

+0

また、関数内で 'global lock'を宣言し、必要に応じてローカル名前空間に特別な検索を保存することもできます。しかし、一般的に、変数を再バインドしていない場合、 'global'キーワードは必要ありません。 – tdelaney

関連する問題