LockおよびRLockオブジェクトを使用する
複数のスレッドが共同で特定のデータを変更すると、予期しない結果が発生する可能性があります。データの正確性を保証するために、複数のスレッドを同期的に変更する必要があります。Pythonプログラムでは、オブジェクトLockおよびRLockを使用します
単純なスレッド同期を実現できます。これらのオブジェクトの両方に、acquireメソッドとreleaseメソッドがあります。一度に1つのスレッドのみを操作する必要があるデータの場合は、acquireメソッドとreleaseメソッドの間に操作を配置できます。
マルチスレッドの利点は、複数のタスクを同時に実行できること(このような感じ)ですが、スレッドがデータを共有する必要がある場合、データの同期が取れないという問題が発生する可能性があります。次のコードは、RLockを使用してスレッド同期を実現する方法を示しています。
import threading import time class mt(threading.Thread): def run(self): global x lock.acquire() for i in range(5): x + = 10 time.sleep(1) print(x) lock.release () x = 0 lock = threading.RLock() def main(): thrs = [] for range in item(8): thrs.append(mt()) for item for thrs :item.start() if __name__ = = '__main__': main()
上記の例では、グローバル変数xにアクセスするためのロックを備えたスレッドクラスmtがカスタマイズされ、メイン関数main()で8つのスレッドが初期化されてxを変更します。一度に1つのスレッドのみがxを操作して効果を実行できます。次のように:
50、100、150 ... Pythonプログラムでは、変数オブジェクトをマルチスレッド環境で安全にしたい場合は、Lockオブジェクトをスレッドで使用して解決できます。次のコードは、クリティカルセクションをロックするロックのプロセスを示しています。
スレッド クラスのインポートShareCounter: def __init __(self、initial_value = 0): self._value = initial_value self._value_lock = threading.Lock() def incr(self、delta = 1): with self._value_lock: self._value + = delta def decr(self、delta = 1): with self._value_lock: self._value-= delta def test(c): for n in range(10000): c.incr() for n for range(10000): c。 decr() if __name__ == ' __main__ ':c = ShareCounter() t1 = threading.Thread(target = test、args =(c、)) t2 = threading.Thread(target = test、args =(c、)) t3 = threading.Thread(target = test、args =(c、)) t1.start() t2.start() t3.start() print( 'Runing test') t1.join() t2.join() t3 .join() assert c._value == 0 print( 'Locks good!'、c._value)#0
上記のコードで、withステートメントを使用すると、Lockオブジェクトは相互に排他的な動作が発生することを保証できます。つまり、withステートメントを実行するために一度に1つのスレッドのみが実行されます。
条件オブジェクトを使用する
Pythonでは、Conditionオブジェクトを使用して、特定のイベントがトリガーされた後、または特定の条件が満たされたときにのみデータを処理できます。Conditionオブジェクトの目的は、複雑なスレッド同期の問題をサポートすることです。
条件は通常、ロックに関連付けられています。複数の条件でロックを共有する必要がある場合は、Lock / RLockインスタンスを渡すことができます。それ以外の場合は、自動的にロックが生成されます。次のコードは
Conditonはかくれんぼゲームを実装しています。1。ゲームが始まると、シーカーは最初に目を覆ってハイダーを支配します; 2.ハイダーは通知を受け取った後、自分を隠してシーカーに見つけられることを通知します。
import threading、time class Hider(threading.Thread): def __init __(self、cond、name): super(Hider、self).__ init __()#最初に親クラスの初期化関数を実行する必要があります。そうしないと、名前が self.cond によって上書きされます= cond self.name = name def run(self): time.sleep(1) #Seekerが最初にself.cond.acquire()を実行していることを確認します#3、ロックを取得し、次の操作を実行します print(「私は目を閉じましたそれだけです! ") Self.cond.notify()#他のユーザーに通知して self.cond.waitのロックを解除して一時停止します() print(self.name、":私はあなたを見つけました ") self.cond.notify() self .cond.release() print(self.name 、 ':I won') class Seeker(threading.Thread): def __init __(self、cond、name): super(Seeker、self).__ init __()#最初に親クラスの初期化関数を実行する必要があります。そうしないと、名前が上書きされます私はあなたの 隠れ家を見つけました:私は勝ちました self.cond = cond self.name = name def run(self): self.cond.acquire()#1、ロックを 取得self.cond.wait()#2、スレッドがハングしている間、ロックの占有を解放し、通知を知っています()そして 、ロックプリントを再度占有します(self.name、 ":隠しました、すぐに見つけてください") self.cond.notify() self.cond.wait() self.cond.release() print (self.name、 ":Found by you、hey") cond = threading.Condition() seeker = Seeker(cond、 'seeker') hider = Hider(cond、 'hider') seeker.start() hider.start () "" " 目を閉じました! シーカー:隠しました、すぐに見つけてください ハイダー:私はあなたを見つけましたシーカー:私はあなたを見つけました 探求者:あなたが見つけた、ちょっと「」「
SemaphoreオブジェクトとBoundedSemaphoreオブジェクトを使用する
Pythonでは、SemaphoreおよびBoundedSemaphoreを使用して、マルチスレッド信号システムのカウンターを制御できます。
1.セマフォ:クラススレッディングセマフォは、パブリックリソースまたはクリティカルセクションへのアクセスを制御するセマフォです。セマフォは、リソースに同時にアクセスするか、クリティカルセクションに入ることができるスレッドの数を指定するカウンターを維持します。
1つのスレッドがシグナルを取得し、カウンターは-1です。カウンターが0の場合、他のスレッドはアクセスを停止します。
スレッドのインポート、時間の 定義 fun(semaphore、num): semaphore.acquire()print( "降龙十八掌、发出%d掌"%num) time.sleep(3) semaphore.release() if __name__ == ' __main__ ': semaphore = threading.Semaphore(2) in num in range(4): t = threading.Thread(target = fun、args =(semaphore、num)) t.start()
実行後、スレッド0と1は同時に実行され、2、3は3秒後に実行されます。
2. BoundedSemaphore:内部カウンターの値をチェックし、初期値より大きくないことを確認します。それを超えると、ValueErrorが発生し、リソースへの制限されたアクセスを保護するためによく使用されます。
イベントオブジェクトを使用
Pythonでは、イベントオブジェクトはスレッド間の最も単純な通信メカニズムの1つであり、スレッドはイベントオブジェクトを待機している他のスレッドをアクティブ化できます。Eventオブジェクトの実装クラスはthreading.Eventです。
これは、イベントオブジェクトを実装するクラスです。イベントはフラグを管理します。フラグは、set()メソッドでtrueに設定するか、clear()メソッドでfalseにリセットできます。wait()メソッドは、フラグがtrueになるまでブロックします。
初期値はfalseです。
import threading、time event = threading.Event() def func(): # print( "%s wait for event ..."%threading.currentThread()。getName()) #event.wait(timeout)妨げ塞线程、イベントオブジェクト内部の実際の実装 位置がTrue、または超時間event.wait() print( "%s recv event。"%threading.currentThread()。getName()) t1 = threading.Thread(target = func) t2 = threading .Thread(target = func) t1.start() t2.start() time.sleep(2) print( "MainTread set event") event.set()#将标识位改是True "" " スレッド1待機イベントの場合... スレッド2のイベント待機... MainTreadセットイベント スレッド2受信イベント。 スレッド1受信イベント。 "" "
Timerオブジェクトを使用する
タイマー:タイマー。指定された時間の後にメソッドを呼び出すために使用されます。対応するタイマーアクションは、cancel()関数によってキャンセルできます。
import threading def func(): print( "ping") timer = threading.Timer(5、func) timer.start()