17.1。 糸脱毛 —スレッドベースの並列処理
ソースコード: :source: `Lib / threading.py`
このモジュールは、下位レベルの _thread モジュールの上に上位レベルのスレッドインターフェイスを構築します。 queue モジュールも参照してください。
ダミースレッドモジュールは、 _thread がないためにスレッドを使用できない状況のために提供されています。
ノート
以下にリストされていませんが、Python2.xシリーズのこのモジュールの一部のメソッドおよび関数に使用されるcamelCase
名は、このモジュールでも引き続きサポートされます。
このモジュールは、次の関数を定義します。
- threading.active_count()
- 現在生きているスレッドオブジェクトの数を返します。 返されるカウントは、 enumerate()によって返されるリストの長さと同じです。
- threading.current_thread()
- 呼び出し元の制御スレッドに対応する、現在の Thread オブジェクトを返します。 呼び出し元の制御スレッドが threading モジュールを介して作成されなかった場合、機能が制限されたダミースレッドオブジェクトが返されます。
- threading.get_ident()
現在のスレッドの「スレッド識別子」を返します。 これはゼロ以外の整数です。 その値には直接的な意味はありません。 使用するマジッククッキーとして意図されています。 スレッド固有のデータのディクショナリにインデックスを付けます。 スレッド識別子は、スレッドが終了して別のスレッドが作成されたときにリサイクルされる場合があります。
バージョン3.3の新機能。
- threading.enumerate()
- 現在生きているすべてのスレッドオブジェクトのリストを返します。 このリストには、デーモンスレッド、 current_thread()によって作成されたダミースレッドオブジェクト、およびメインスレッドが含まれています。 終了したスレッドとまだ開始されていないスレッドは除外されます。
- threading.main_thread()
メインのスレッドオブジェクトを返します。 通常の状態では、メインスレッドはPythonインタープリターが開始されたスレッドです。
バージョン3.4の新機能。
- threading.settrace(func)
- threading モジュールから開始したすべてのスレッドにトレース機能を設定します。 func は、 run()メソッドが呼び出される前に、各スレッドの sys.settrace()に渡されます。
- threading.setprofile(func)
- threading モジュールから開始するすべてのスレッドにプロファイル関数を設定します。 func は、 run()メソッドが呼び出される前に、各スレッドの sys.setprofile()に渡されます。
- threading.stack_size([size])
- 新しいスレッドを作成するときに使用されるスレッドスタックサイズを返します。 オプションの size 引数は、後で作成されるスレッドに使用されるスタックサイズを指定し、0(プラットフォームまたは構成済みのデフォルトを使用)または少なくとも32,768(32 KiB)の正の整数値である必要があります。 size が指定されていない場合、0が使用されます。 スレッドスタックサイズの変更がサポートされていない場合、 RuntimeError が発生します。 指定されたスタックサイズが無効な場合、 ValueError が発生し、スタックサイズは変更されません。 32 KiBは現在、インタプリタ自体に十分なスタックスペースを保証するためにサポートされている最小スタックサイズ値です。 一部のプラットフォームでは、32 KiBを超える最小スタックサイズが必要な場合や、システムメモリページサイズの倍数での割り当てが必要な場合など、スタックサイズの値に特定の制限がある場合があることに注意してください。詳細については、プラットフォームのドキュメントを参照してください(4 KiBページ)。一般的です。より具体的な情報がない場合は、スタックサイズに4096の倍数を使用することをお勧めします)。 可用性:Windows、POSIXスレッドを備えたシステム。
このモジュールは、次の定数も定義します。
- threading.TIMEOUT_MAX
ブロッキング関数の timeout パラメーターに許可される最大値( Lock.acquire()、 RLock.acquire()、 Condition.wait() など)。 この値より大きいタイムアウトを指定すると、 OverflowError が発生します。
バージョン3.2の新機能。
このモジュールは、以下のセクションで詳しく説明するいくつかのクラスを定義します。
このモジュールの設計は、Javaのスレッドモデルに大まかに基づいています。 ただし、Javaがロックと条件変数をすべてのオブジェクトの基本的な動作にする場合、それらはPythonでは個別のオブジェクトです。 Pythonの Thread クラスは、JavaのThreadクラスの動作のサブセットをサポートします。 現在、優先順位やスレッドグループはなく、スレッドを破棄、停止、一時停止、再開、または中断することはできません。 JavaのThreadクラスの静的メソッドは、実装されると、モジュールレベルの関数にマップされます。
以下で説明するすべてのメソッドは、アトミックに実行されます。
17.1.1。 スレッドローカルデータ
スレッドローカルデータは、値がスレッド固有のデータです。 スレッドローカルデータを管理するには、 local (またはサブクラス)のインスタンスを作成し、それに属性を格納するだけです。
mydata = threading.local()
mydata.x = 1
インスタンスの値は、スレッドごとに異なります。
- class threading.local
スレッドローカルデータを表すクラス。
詳細と広範な例については、
_threading_local
モジュールのドキュメント文字列を参照してください。
17.1.2。 スレッドオブジェクト
Thread クラスは、別の制御スレッドで実行されるアクティビティを表します。 アクティビティを指定するには、呼び出し可能なオブジェクトをコンストラクターに渡す方法と、サブクラスの run()メソッドをオーバーライドする方法の2つがあります。 サブクラスでは、他のメソッド(コンストラクターを除く)をオーバーライドしないでください。 つまり、のみは、このクラスの__init__()
および run()メソッドをオーバーライドします。
スレッドオブジェクトが作成されたら、スレッドの start()メソッドを呼び出してそのアクティビティを開始する必要があります。 これにより、別の制御スレッドで run()メソッドが呼び出されます。
スレッドのアクティビティが開始されると、スレッドは「生きている」と見なされます。 run()メソッドが終了すると、通常どおり、または未処理の例外を発生させることにより、動作を停止します。 is_alive()メソッドは、スレッドが生きているかどうかをテストします。
他のスレッドは、スレッドの join()メソッドを呼び出すことができます。 これにより、 join()メソッドが呼び出されたスレッドが終了するまで、呼び出し元のスレッドがブロックされます。
スレッドには名前があります。 名前はコンストラクターに渡され、 name 属性を介して読み取ったり変更したりできます。
スレッドは「デーモンスレッド」としてフラグを立てることができます。 このフラグの重要性は、デーモンスレッドのみが残っているときにPythonプログラム全体が終了することです。 初期値は作成スレッドから継承されます。 フラグは、デーモンプロパティまたはデーモンコンストラクター引数を介して設定できます。
ノート
デーモンスレッドは、シャットダウン時に突然停止します。 それらのリソース(開いているファイル、データベーストランザクションなど)が適切に解放されない場合があります。 スレッドを正常に停止させたい場合は、スレッドを非デーモンにし、 Event などの適切なシグナリングメカニズムを使用します。
「メインスレッド」オブジェクトがあります。 これは、Pythonプログラムの最初の制御スレッドに対応します。 デーモンスレッドではありません。
「ダミースレッドオブジェクト」が作成される可能性があります。 これらは「エイリアンスレッド」に対応するスレッドオブジェクトであり、Cコードから直接など、スレッドモジュールの外部で開始される制御スレッドです。 ダミースレッドオブジェクトの機能は制限されています。 それらは常に生きていてデーモン的であると見なされ、 join()することはできません。 エイリアンスレッドの終了を検出することは不可能であるため、これらが削除されることはありません。
- class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
このコンストラクターは、常にキーワード引数を使用して呼び出す必要があります。 引数は次のとおりです。
グループは
None
である必要があります。ThreadGroup
クラスが実装されたときの将来の拡張のために予約されています。target は、 run()メソッドによって呼び出される呼び出し可能なオブジェクトです。 デフォルトは
None
で、何も呼び出されないことを意味します。name はスレッド名です。 デフォルトでは、一意の名前は「Thread- N 」の形式で構成されます。ここで、 N は小さな10進数です。
args は、ターゲット呼び出しの引数タプルです。 デフォルトは
()
です。kwargs は、ターゲット呼び出しのキーワード引数の辞書です。 デフォルトは
{}
です。None
でない場合、デーモンはスレッドがデーモンであるかどうかを明示的に設定します。None
(デフォルト)の場合、デーモンプロパティは現在のスレッドから継承されます。サブクラスがコンストラクターをオーバーライドする場合、スレッドに対して他のことを行う前に、必ず基本クラスのコンストラクター(
Thread.__init__()
)を呼び出す必要があります。バージョン3.3で変更: デーモン引数が追加されました。
- start()
スレッドのアクティビティを開始します。
スレッドオブジェクトごとに最大1回呼び出す必要があります。 これは、オブジェクトの run()メソッドが別の制御スレッドで呼び出されるように調整します。
このメソッドは、同じスレッドオブジェクトで複数回呼び出された場合、 RuntimeError を発生させます。
- run()
スレッドのアクティビティを表すメソッド。
サブクラスでこのメソッドをオーバーライドできます。 標準の run()メソッドは、オブジェクトのコンストラクターに渡された呼び出し可能オブジェクトを target 引数として呼び出し、 args からシーケンシャル引数とキーワード引数を取得します。それぞれ kwargs 引数。
- join(timeout=None)
スレッドが終了するまで待ちます。 これにより、 join()メソッドが呼び出されたスレッドが終了するまで(通常または未処理の例外によって)、またはオプションのタイムアウトが発生するまで、呼び出し元のスレッドがブロックされます。
timeout 引数が存在し、
None
が存在しない場合は、操作のタイムアウトを秒単位(またはその端数)で指定する浮動小数点数である必要があります。 join()は常にNone
を返すため、 join()の後に is_alive()を呼び出して、タイムアウトが発生したかどうかを判断する必要があります。スレッドはまだ生きています、 join()呼び出しはタイムアウトしました。timeout 引数が存在しないか
None
の場合、スレッドが終了するまで操作はブロックされます。スレッドは何度も join()することができます。
join()は、現在のスレッドに参加しようとするとデッドロックが発生するため、 RuntimeError を発生させます。 スレッドが開始される前に join()することもエラーであり、そうしようとすると同じ例外が発生します。
- name
識別目的でのみ使用される文字列。 セマンティクスはありません。 複数のスレッドに同じ名前を付けることができます。 初期名はコンストラクターによって設定されます。
- getName()
setName() name の古いゲッター/セッターAPI; 代わりに、プロパティとして直接使用してください。
- ident
このスレッドの「スレッド識別子」、またはスレッドが開始されていない場合は
None
。 これはゼロ以外の整数です。 get_ident()関数を参照してください。 スレッド識別子は、スレッドが終了して別のスレッドが作成されたときにリサイクルされる場合があります。 識別子は、スレッドが終了した後でも使用できます。
- is_alive()
スレッドが生きているかどうかを返します。
このメソッドは、 run()メソッドが開始する直前から run()メソッドが終了する直前まで、
True
を返します。 モジュール関数 enumerate()は、生きているすべてのスレッドのリストを返します。
- daemon
このスレッドがデーモンスレッドであるか(True)、そうでないか(False)を示すブール値。 これは、 start()が呼び出される前に設定する必要があります。そうしないと、 RuntimeError が発生します。 その初期値は作成スレッドから継承されます。 メインスレッドはデーモンスレッドではないため、メインスレッドで作成されるすべてのスレッドはデフォルトでデーモン =
False
になります。デーモン以外のスレッドが残っていない場合、Pythonプログラム全体が終了します。
- isDaemon()
setDaemon() デーモン用の古いゲッター/セッターAPI; 代わりに、プロパティとして直接使用してください。
17.1.3。 オブジェクトをロックする
プリミティブロックは、ロックされたときに特定のスレッドによって所有されない同期プリミティブです。 Pythonでは、これは現在利用可能な最低レベルの同期プリミティブであり、 _thread 拡張モジュールによって直接実装されます。
プリミティブロックは、「ロック」または「ロック解除」の2つの状態のいずれかになります。 ロック解除状態で作成されます。 accept()と release()の2つの基本的なメソッドがあります。 状態がロック解除されると、 accept()は状態をロックに変更し、すぐに戻ります。 状態がロックされると、 accept()は、別のスレッドで release()を呼び出すとロックが解除されるまでブロックされ、 accept()呼び出しがリセットされます。ロックして戻ります。 release()メソッドは、ロックされた状態でのみ呼び出す必要があります。 状態をロック解除に変更し、すぐに戻ります。 ロック解除されたロックを解放しようとすると、 RuntimeError が発生します。
ロックは、コンテキスト管理プロトコルもサポートします。
状態がロック解除に変わるのを待っている acquire()で複数のスレッドがブロックされている場合、 release()呼び出しが状態をロック解除にリセットすると、1つのスレッドのみが進行します。 待機中のスレッドのどれが進行するかは定義されておらず、実装によって異なる場合があります。
すべてのメソッドはアトミックに実行されます。
- class threading.Lock
プリミティブロックオブジェクトを実装するクラス。 スレッドがロックを取得すると、それ以降は、解放されるまでブロックを取得しようとします。 どのスレッドでもそれを解放できます。
Lock
は実際には、プラットフォームでサポートされている具象Lockクラスの最も効率的なバージョンのインスタンスを返すファクトリ関数であることに注意してください。- acquire(blocking=True, timeout=- 1)
ロック、ブロッキング、または非ブロッキングを取得します。
blocking 引数を
True
(デフォルト)に設定して呼び出すと、ロックが解除されるまでブロックしてから、lockedに設定してTrue
を返します。blocking 引数を
False
に設定して呼び出す場合は、ブロックしないでください。 blocking がTrue
に設定されている呼び出しがブロックされる場合は、すぐにFalse
を返します。 それ以外の場合は、ロックをロックに設定し、True
を返します。浮動小数点 timeout 引数を正の値に設定して呼び出された場合、 timeout で指定された最大秒数の間、ロックを取得できない限りブロックします。
-1
の timeout 引数は、無制限の待機を指定します。 ブロッキングがfalseの場合、タイムアウトを指定することは禁止されています。ロックが正常に取得された場合、戻り値は
True
であり、そうでない場合(たとえば、タイムアウトの期限が切れた場合)はFalse
です。バージョン3.2で変更: timeout パラメーターが新しくなりました。
バージョン3.2での変更:基盤となるスレッド実装がサポートしている場合、POSIX上のシグナルによってロック取得を中断できるようになりました。
- release()
ロックを解除します。 これは、ロックを取得したスレッドだけでなく、任意のスレッドから呼び出すことができます。
ロックがロックされたら、ロック解除にリセットしてから戻ります。 ロックがロック解除されるのを待って他のスレッドがブロックされている場合は、そのうちの1つだけを続行させます。
ロック解除されたロックで呼び出されると、 RuntimeError が発生します。
戻り値はありません。
17.1.4。 RLockオブジェクト
再入可能ロックは、同じスレッドによって複数回取得される可能性のある同期プリミティブです。 内部的には、プリミティブロックで使用されるロック/ロック解除状態に加えて、「スレッドの所有」と「再帰レベル」の概念を使用します。 ロック状態では、一部のスレッドがロックを所有しています。 ロック解除状態では、スレッドはそれを所有しません。
ロックをロックするために、スレッドはその accept()メソッドを呼び出します。 これは、スレッドがロックを所有すると戻ります。 ロックを解除するために、スレッドはその release()メソッドを呼び出します。 accept() / release()呼び出しペアはネストできます。 最後の release()(最も外側のペアの release())のみがロックをロック解除にリセットし、 accept()でブロックされた別のスレッドが続行できるようにします。
再入可能ロックは、コンテキスト管理プロトコルもサポートします。
- class threading.RLock
このクラスは、再入可能なロックオブジェクトを実装します。 再入可能ロックは、それを取得したスレッドによって解放される必要があります。 スレッドが再入可能ロックを取得すると、同じスレッドがブロックせずに再度取得できます。 スレッドは、取得するたびに1回解放する必要があります。
RLock
は実際には、プラットフォームでサポートされている具象RLockクラスの最も効率的なバージョンのインスタンスを返すファクトリ関数であることに注意してください。- acquire(blocking=True, timeout=- 1)
ロック、ブロッキング、または非ブロッキングを取得します。
引数なしで呼び出された場合:このスレッドがすでにロックを所有している場合は、再帰レベルを1つインクリメントして、すぐに戻ります。 それ以外の場合、別のスレッドがロックを所有している場合は、ロックがロック解除されるまでブロックします。 ロックのロックが解除されたら(どのスレッドも所有していない)、所有権を取得し、再帰レベルを1に設定して、戻ります。 ロックがロック解除されるまで待機している複数のスレッドがブロックされている場合、一度に1つだけがロックの所有権を取得できます。 この場合、戻り値はありません。
blocking 引数をtrueに設定して呼び出された場合は、引数なしで呼び出された場合と同じことを行い、trueを返します。
blocking 引数をfalseに設定して呼び出された場合、ブロックしないでください。 引数のない呼び出しがブロックされる場合は、すぐにfalseを返します。 それ以外の場合は、引数なしで呼び出されたときと同じことを行い、trueを返します。
浮動小数点 timeout 引数を正の値に設定して呼び出された場合、 timeout で指定された最大秒数の間、ロックを取得できない限りブロックします。 ロックが取得されている場合はtrueを返し、タイムアウトが経過した場合はfalseを返します。
バージョン3.2で変更: timeout パラメーターが新しくなりました。
- release()
ロックを解除し、再帰レベルを下げます。 デクリメント後にゼロの場合は、ロックをロック解除にリセットし(どのスレッドも所有していない)、ロックがロック解除されるのを待って他のスレッドがブロックされている場合は、そのうちの1つだけを続行します。 デクリメント後も再帰レベルがゼロ以外の場合、ロックはロックされたままで、呼び出し元のスレッドによって所有されます。
このメソッドは、呼び出し元のスレッドがロックを所有している場合にのみ呼び出してください。 ロックがロック解除されているときにこのメソッドが呼び出されると、 RuntimeError が発生します。
戻り値はありません。
17.1.5。 条件オブジェクト
条件変数は常にある種のロックに関連付けられています。 これは渡すことができます。または、デフォルトで作成されます。 1つを渡すと、複数の条件変数が同じロックを共有する必要がある場合に役立ちます。 ロックは条件オブジェクトの一部です。個別に追跡する必要はありません。
条件変数は、コンテキスト管理プロトコルに従います。with
ステートメントを使用すると、囲まれたブロックの期間中、関連するロックが取得されます。 accept()および release()メソッドも、関連するロックの対応するメソッドを呼び出します。
他のメソッドは、関連するロックを保持したまま呼び出す必要があります。 wait()メソッドはロックを解放し、 notify()または notify_all()を呼び出して、別のスレッドがロックを解除するまでブロックします。 覚醒すると、 wait()はロックを再取得して戻ります。 タイムアウトを指定することもできます。
notify()メソッドは、条件変数を待機しているスレッドの1つをウェイクアップします(待機している場合)。 notify_all()メソッドは、条件変数を待機しているすべてのスレッドをウェイクアップします。
注: notify()および notify_all()メソッドはロックを解放しません。 これは、ウェイクアップされた1つまたは複数のスレッドが wait()呼び出しからすぐに戻るのではなく、 notify()または notify_all()[X268X ]最終的にロックの所有権を放棄します。
条件変数を使用する一般的なプログラミングスタイルでは、ロックを使用して、ある共有状態へのアクセスを同期します。 特定の状態変化に関心のあるスレッドは、目的の状態が表示されるまで wait()を繰り返し呼び出しますが、状態を変更するスレッドは notify()または notify_all( )ウェイターの1人にとって望ましい状態になる可能性があるような方法で状態を変更した場合。 たとえば、次のコードは、バッファ容量が無制限の一般的な生産者/消費者の状況です。
# Consume one item
with cv:
while not an_item_is_available():
cv.wait()
get_an_available_item()
# Produce one item
with cv:
make_an_item_available()
cv.notify()
wait()は任意の長い時間の後に戻る可能性があり、 notify()呼び出しを促した条件が発生する可能性があるため、アプリケーションの状態をチェックするwhile
ループが必要です。もはや当てはまりません。 これは、マルチスレッドプログラミングに固有のものです。 wait_for()メソッドを使用して、条件チェックを自動化し、タイムアウトの計算を容易にすることができます。
# Consume an item
with cv:
cv.wait_for(an_item_is_available)
get_an_available_item()
notify()と notify_all()のどちらかを選択するには、1つの状態変化が1つまたは複数の待機中のスレッドに対してのみ興味深いかどうかを検討してください。 例えば 典型的な生産者/消費者の状況では、バッファに1つのアイテムを追加するだけで、1つのコンシューマスレッドをウェイクアップする必要があります。
- class threading.Condition(lock=None)
このクラスは、条件変数オブジェクトを実装します。 条件変数を使用すると、1つ以上のスレッドが別のスレッドから通知されるまで待機できます。
lock 引数が指定され、
None
ではない場合、それは Lock または RLock オブジェクトである必要があり、基になるロックとして使用されます。 それ以外の場合は、新しい RLock オブジェクトが作成され、基になるロックとして使用されます。バージョン3.3で変更:ファクトリ関数からクラスに変更されました。
- acquire(*args)
基になるロックを取得します。 このメソッドは、基になるロックの対応するメソッドを呼び出します。 戻り値は、そのメソッドが返すものです。
- release()
基になるロックを解放します。 このメソッドは、基になるロックの対応するメソッドを呼び出します。 戻り値はありません。
- wait(timeout=None)
通知されるまで、またはタイムアウトが発生するまで待ちます。 このメソッドが呼び出されたときに呼び出し元のスレッドがロックを取得していない場合、 RuntimeError が発生します。
このメソッドは、基になるロックを解放し、別のスレッドで同じ条件変数に対する notify()または notify_all()呼び出しによってウェイクアップされるまで、またはオプションのタイムアウトまでブロックします。発生します。 目覚めたりタイムアウトしたりすると、ロックを再取得して戻ります。
timeout 引数が存在し、
None
が存在しない場合は、操作のタイムアウトを秒単位(またはその端数)で指定する浮動小数点数である必要があります。基になるロックが RLock の場合、 release()メソッドを使用して解放されません。これは、再帰的に複数回取得されたときに実際にロックのロックが解除されない可能性があるためです。 代わりに、 RLock クラスの内部インターフェイスが使用されます。これにより、再帰的に何度も取得された場合でも、実際にロックが解除されます。 次に、別の内部インターフェイスを使用して、ロックが再取得されたときに再帰レベルを復元します。
指定された timeout が期限切れにならない限り、戻り値は
True
です。期限切れの場合は、False
です。バージョン3.2で変更:以前は、メソッドは常に
None
を返していました。
- wait_for(predicate, timeout=None)
条件がtrueと評価されるまで待ちます。 述語は呼び出し可能である必要があり、その結果はブール値として解釈されます。 タイムアウトを指定して、最大待機時間を与えることができます。
このユーティリティメソッドは、述語が満たされるまで、またはタイムアウトが発生するまで、 wait()を繰り返し呼び出すことができます。 戻り値は述語の最後の戻り値であり、メソッドがタイムアウトした場合は
False
と評価されます。タイムアウト機能を無視すると、このメソッドを呼び出すことは、次のように記述することとほぼ同じです。
while not predicate(): cv.wait()
したがって、 wait()の場合と同じルールが適用されます。ロックは呼び出されたときに保持する必要があり、戻ったときに再取得されます。 述部は、ロックが保持された状態で評価されます。
バージョン3.2の新機能。
- notify(n=1)
デフォルトでは、この状態で待機している1つのスレッドをウェイクアップします(存在する場合)。 このメソッドが呼び出されたときに呼び出し元のスレッドがロックを取得していない場合、 RuntimeError が発生します。
このメソッドは、条件変数を待機しているスレッドの最大 n をウェイクアップします。 待機しているスレッドがない場合は、何もしません。
現在の実装は、少なくとも n スレッドが待機している場合、正確に n スレッドをウェイクアップします。 ただし、この動作に依存することは安全ではありません。 将来、最適化された実装では、 n スレッドよりも多くのスレッドがウェイクアップする場合があります。
注:ウェイクアップされたスレッドは、ロックを再取得できるようになるまで、 wait()呼び出しから実際には戻りません。 notify()はロックを解放しないため、呼び出し元は解放する必要があります。
- notify_all()
この状態で待機しているすべてのスレッドをウェイクアップします。 このメソッドは notify()のように機能しますが、待機中のスレッドを1つではなくすべてウェイクアップします。 このメソッドが呼び出されたときに呼び出し元のスレッドがロックを取得していない場合、 RuntimeError が発生します。
17.1.6。 セマフォオブジェクト
これは、初期のオランダのコンピューター科学者Edsger Wによって発明された、コンピューターサイエンスの歴史の中で最も古い同期プリミティブの1つです。 ダイクストラ(彼は accept()と release()の代わりにP()
とV()
という名前を使用しました)。
セマフォは、 accept()呼び出しごとにデクリメントされ、 release()呼び出しごとにインクリメントされる内部カウンターを管理します。 カウンターがゼロを下回ることはありません。 accept()がゼロを検出すると、ブロックし、他のスレッドが release()を呼び出すまで待機します。
セマフォは、コンテキスト管理プロトコルもサポートします。
- class threading.Semaphore(value=1)
このクラスは、セマフォオブジェクトを実装します。 セマフォは、 release()呼び出しの数から accept()呼び出しの数を引いた数に、初期値を加えたものを表すアトミックカウンターを管理します。 accept()メソッドは、必要に応じて、カウンターを負にせずに戻ることができるまでブロックします。 指定しない場合、 value のデフォルトは1です。
オプションの引数は、内部カウンターの初期値を示します。 デフォルトは
1
です。 指定された value が0未満の場合、 ValueError が発生します。バージョン3.3で変更:ファクトリ関数からクラスに変更されました。
- acquire(blocking=True, timeout=None)
セマフォを取得します。
引数なしで呼び出された場合:
入力時に内部カウンタがゼロより大きい場合は、1ずつデクリメントして、すぐにtrueを返します。
エントリ時に内部カウンタがゼロの場合は、 release()の呼び出しによって起動されるまでブロックします。 目覚めたら(そしてカウンターが0より大きい場合)、カウンターを1デクリメントし、trueを返します。 release()を呼び出すたびに、正確に1つのスレッドが呼び出されます。 スレッドが起こされる順序は信頼されるべきではありません。
ブロックをfalseに設定して呼び出された場合、ブロックしないでください。 引数のない呼び出しがブロックされる場合は、すぐにfalseを返します。 それ以外の場合は、引数なしで呼び出されたときと同じことを行い、trueを返します。
None
以外の timeout で呼び出された場合、最大 timeout 秒間ブロックされます。 その間隔で取得が正常に完了しない場合は、falseを返します。 それ以外の場合はtrueを返します。バージョン3.2で変更: timeout パラメーターが新しくなりました。
- release()
セマフォを解放し、内部カウンタを1つインクリメントします。 エントリ時にゼロであり、別のスレッドが再びゼロより大きくなるのを待っているときに、そのスレッドをウェイクアップします。
- class threading.BoundedSemaphore(value=1)
制限付きセマフォオブジェクトを実装するクラス。 制限付きセマフォは、現在の値が初期値を超えていないことを確認します。 含まれている場合、 ValueError が発生します。 ほとんどの場合、セマフォは容量が限られているリソースを保護するために使用されます。 セマフォが何度もリリースされる場合は、バグの兆候です。 指定しない場合、 value のデフォルトは1です。
バージョン3.3で変更:ファクトリ関数からクラスに変更されました。
17.1.6.1。 セマフォ例
セマフォは、データベースサーバーなど、容量が限られているリソースを保護するためによく使用されます。 リソースのサイズが固定されている状況では、制限付きセマフォを使用する必要があります。 ワーカースレッドを生成する前に、メインスレッドはセマフォを初期化します。
maxconnections = 5
# ...
pool_sema = BoundedSemaphore(value=maxconnections)
生成されると、ワーカースレッドは、サーバーに接続する必要があるときに、セマフォの取得メソッドと解放メソッドを呼び出します。
with pool_sema:
conn = connectdb()
try:
# ... use connection ...
finally:
conn.close()
制限付きセマフォを使用すると、セマフォが取得された以上に解放される原因となるプログラミングエラーが検出されなくなる可能性が低くなります。
17.1.7。 イベントオブジェクト
これは、スレッド間の通信のための最も単純なメカニズムの1つです。1つのスレッドがイベントを通知し、他のスレッドがそれを待機します。
イベントオブジェクトは、 set()メソッドでtrueに設定し、 clear()メソッドでfalseにリセットできる内部フラグを管理します。 wait()メソッドは、フラグがtrueになるまでブロックします。
- class threading.Event
イベントオブジェクトを実装するクラス。 イベントは、 set()メソッドでtrueに設定し、 clear()メソッドでfalseにリセットできるフラグを管理します。 wait()メソッドは、フラグがtrueになるまでブロックします。 フラグは最初はfalseです。
バージョン3.3で変更:ファクトリ関数からクラスに変更されました。
- is_set()
内部フラグがtrueの場合にのみ、trueを返します。
- set()
内部フラグをtrueに設定します。 それが真になるのを待っているすべてのスレッドが目覚めます。 フラグがtrueになると wait()を呼び出すスレッドは、まったくブロックされません。
- wait(timeout=None)
内部フラグが真になるまでブロックします。 エントリ時に内部フラグがtrueの場合は、すぐに戻ります。 それ以外の場合は、別のスレッドが set()を呼び出してフラグをtrueに設定するまで、またはオプションのタイムアウトが発生するまでブロックします。
None
ではなくtimeout引数が存在する場合は、操作のタイムアウトを秒単位(またはその一部)で指定する浮動小数点数である必要があります。このメソッドは、待機呼び出しの前または待機開始後に内部フラグがtrueに設定されている場合にのみtrueを返すため、タイムアウトが指定されて操作がタイムアウトした場合を除き、常に
True
を返します。 。バージョン3.1で変更:以前は、メソッドは常に
None
を返していました。
17.1.8。 タイマーオブジェクト
このクラスは、一定の時間が経過した後にのみ実行する必要があるアクション、つまりタイマーを表します。 Timer は Thread のサブクラスであり、カスタムスレッドを作成する例としても機能します。
タイマーは、スレッドと同様に、start()
メソッドを呼び出すことによって開始されます。 cancel()メソッドを呼び出すことにより、タイマーを(アクションが開始する前に)停止できます。 タイマーがアクションを実行する前に待機する間隔は、ユーザーが指定した間隔と完全に同じではない場合があります。
例えば:
def hello():
print("hello, world")
t = Timer(30.0, hello)
t.start() # after 30 seconds, "hello, world" will be printed
- class threading.Timer(interval, function, args=None, kwargs=None)
間隔秒が経過した後、引数 args とキーワード引数 kwargs で関数を実行するタイマーを作成します。 args が
None
(デフォルト)の場合、空のリストが使用されます。 kwargs がNone
(デフォルト)の場合、空のdictが使用されます。バージョン3.3で変更:ファクトリ関数からクラスに変更されました。
- cancel()
タイマーを停止し、タイマーのアクションの実行をキャンセルします。 これは、タイマーがまだ待機段階にある場合にのみ機能します。
17.1.9。 バリアオブジェクト
バージョン3.2の新機能。
このクラスは、相互に待機する必要がある固定数のスレッドが使用するための単純な同期プリミティブを提供します。 各スレッドは、 wait()メソッドを呼び出してバリアを通過しようとし、すべてのスレッドが wait()呼び出しを行うまでブロックします。 この時点で、スレッドは同時に解放されます。
バリアは、同じ数のスレッドに対して何度でも再利用できます。
例として、クライアントスレッドとサーバースレッドを同期する簡単な方法を次に示します。
b = Barrier(2, timeout=5)
def server():
start_server()
b.wait()
while True:
connection = accept_connection()
process_server_connection(connection)
def client():
b.wait()
while True:
connection = make_connection()
process_client_connection(connection)
- class threading.Barrier(parties, action=None, timeout=None)
partys スレッド数のバリアオブジェクトを作成します。 アクションが提供されている場合、それらが解放されたときにスレッドの1つによって呼び出される呼び出し可能です。 timeout は、 wait()メソッドに何も指定されていない場合のデフォルトのタイムアウト値です。
- wait(timeout=None)
障壁を通過します。 バリアに関係するすべてのスレッドがこの関数を呼び出すと、それらはすべて同時に解放されます。 timeout が指定されている場合、クラスコンストラクターに指定されたものよりも優先して使用されます。
戻り値は0から parties – 1の範囲の整数で、スレッドごとに異なります。 これを使用して、特別なハウスキーピングを行うスレッドを選択できます。例:
i = barrier.wait() if i == 0: # Only one thread needs to print this print("passed the barrier")
action がコンストラクターに提供された場合、スレッドの1つが解放される前にそれを呼び出します。 この呼び出しでエラーが発生した場合、バリアは壊れた状態になります。
通話がタイムアウトすると、バリアは壊れた状態になります。
このメソッドは、スレッドの待機中にバリアが壊れたりリセットされたりした場合に、 BrokenBarrierError 例外を発生させる可能性があります。
- reset()
バリアをデフォルトの空の状態に戻します。 それを待機しているスレッドは、 BrokenBarrierError 例外を受け取ります。
状態が不明な他のスレッドがある場合、この関数を使用すると、外部同期が必要になる場合があることに注意してください。 障壁が壊れた場合は、そのままにして新しい障壁を作成する方がよい場合があります。
- abort()
バリアを壊れた状態にします。 これにより、 wait()へのアクティブまたは将来の呼び出しは、 BrokenBarrierError で失敗します。 たとえば、アプリケーションのデッドロックを回避するために、いずれかを中止する必要がある場合にこれを使用します。
賢明な timeout 値を使用してバリアを作成し、スレッドの1つが失敗するのを自動的に防ぐことが望ましい場合があります。
- parties
バリアを通過するために必要なスレッドの数。
- n_waiting
バリアで現在待機しているスレッドの数。
- broken
バリアが壊れた状態の場合、
True
のブール値。
- exception threading.BrokenBarrierError
- この例外、 RuntimeError のサブクラスは、 Barrier オブジェクトがリセットまたは破損したときに発生します。
17.1.10。 でロック、条件、およびセマフォを使用すると声明
acquire()
およびrelease()
メソッドを持つこのモジュールによって提供されるすべてのオブジェクトは、 with ステートメントのコンテキストマネージャーとして使用できます。 acquire()
メソッドは、ブロックに入るときに呼び出され、release()
は、ブロックが出るときに呼び出されます。 したがって、次のスニペット:
with some_lock:
# do something...
と同等です:
some_lock.acquire()
try:
# do something...
finally:
some_lock.release()
現在、 Lock 、 RLock 、 Condition 、 Semaphore 、および BoundedSemaphore オブジェクトをとして使用できます。 with ステートメントコンテキストマネージャー。