同期プリミティブ

ソースコード: Lib/asyncio/locks.py


asyncio の同期プリミティブは threading モジュールのそれと類似するようにデザインされていますが、2つの重要な注意事項があります:

  • asyncio の同期プリミティブはスレッドセーフではありません。従って OS スレッドの同期に使うべきではありません (代わりに threading を使ってください);

  • 同期プリミティブのメソッドは timeout 引数を受け付けません; タイムアウトを伴う操作を実行するには asyncio.wait_for() 関数を使ってください。

asyncio モジュールは以下の基本的な同期プリミティブを持っています:


Lock

class asyncio.Lock(*, loop=None)

asyncio タスクのためのミューテックスロックを実装しています。スレッドセーフではありません。

asyncio ロックは、共有リソースに対する排他的なアクセスを保証するために使うことができます。

Lock の望ましい使用方法は、 async with 文と組み合わせて使うことです:

lock = asyncio.Lock()

# ... later
async with lock:
    # access shared state

これは以下のコードと等価です:

lock = asyncio.Lock()

# ... later
await lock.acquire()
try:
    # access shared state
finally:
    lock.release()

Deprecated since version 3.8, will be removed in version 3.10: loop パラメータ。

coroutine acquire()

ロックを獲得します。

このメソッドはロックが 解除される まで待機し、ロックを ロック状態 に変更して True を返します。

複数のコルーチンが acquire() メソッドによりロックの解除を待ち受けている場合、最終的にただひとつのコルーチンが実行されます。

ロックの獲得は 公平 です: すなわちロックを獲得して実行されるコルーチンは、最初にロックの待ち受けを開始したコルーチンです。

release()

ロックを解放します。

ロックが ロック状態 の場合、 ロックを 解除状態 にしてリターンします。

ロックが 解除状態 の場合、 RuntimeError 例外が送出されます。

locked()

ロック状態 の場合に True を返します。

Event

class asyncio.Event(*, loop=None)

イベントオブジェクトです。スレッドセーフではありません。

asyncio イベントは、複数の asyncio タスクに対して何らかのイベントが発生したことを通知するために使うことができます。

Event オブジェクトは内部フラグを管理します。フラグの値は set() メソッドにより true に、また clear() メソッドにより false に設定することができます。 wait() メソッドはフラグが true になるまで処理をブロックします。フラグの初期値は false です。

Deprecated since version 3.8, will be removed in version 3.10: loop パラメータ。

以下はプログラム例です:

async def waiter(event):
    print('waiting for it ...')
    await event.wait()
    print('... got it!')

async def main():
    # Create an Event object.
    event = asyncio.Event()

    # Spawn a Task to wait until 'event' is set.
    waiter_task = asyncio.create_task(waiter(event))

    # Sleep for 1 second and set the event.
    await asyncio.sleep(1)
    event.set()

    # Wait until the waiter task is finished.
    await waiter_task

asyncio.run(main())
coroutine wait()

イベントがセットされるまで待機します。

イベントがセットされると、即座に True を返します。 そうでなければ、他のタスクが set() メソッドを呼び出すまで処理をブロックします。

set()

イベントをセットします。

イベントがセットされるまで待機している全てのタスクは、即座に通知を受けて実行を再開します。

clear()

イベントをクリア (アンセット) します

wait() メソッドで待ち受けを行うタスクは set() メソッドが再度呼び出されるまで処理をブロックします。

is_set()

イベントがセットされている場合 True を返します。

Condition

class asyncio.Condition(lock=None, *, loop=None)

条件変数オブジェクトです。スレッドセーフではありません。

asyncio 条件プリミティブは何らかのイベントが発生するのを待ち受け、そのイベントを契機として共有リソースへの排他的なアクセスを得るために利用することができます。

本質的に、 Condition オブジェクトは Event と a Lock の2つのクラスの機能を組み合わせたものです。複数の Condition オブジェクトが単一の Lock を共有することでができます。これにより、共有リソースのそれぞれの状態に関連する異なるタスクの間で、そのリソースへの排他的アクセスを調整することが可能になります。

オプション引数 lockLock または None でなければなりません。後者の場合自動的に新しい Lock オブジェクトが生成されます。

Deprecated since version 3.8, will be removed in version 3.10: loop パラメータ。

Condition の望ましい使用方法は async with 文と組み合わせて使うことです:

cond = asyncio.Condition()

# ... later
async with cond:
    await cond.wait()

これは以下のコードと等価です:

cond = asyncio.Condition()

# ... later
await cond.acquire()
try:
    await cond.wait()
finally:
    cond.release()
coroutine acquire()

下層でのロックを獲得します。

このメソッドは下層のロックが 解除される まで待機し、ロックを ロック状態 に変更して True を返します。

notify(n=1)

この条件を待ち受けている最大で n 個のタスク (n のデフォルト値は 1) を起動します。待ち受けているタスクがいない場合、このメソッドは何もしません。

このメソッドが呼び出される前にロックを獲得しておかなければなりません。また、メソッド呼び出し後速やかにロックを解除しなければなりません。 解除された ロックとと共に呼び出された場合、 RuntimeError 例外が送出されます。

locked()

下層のロックを獲得していれば True を返します。

notify_all()

この条件を待ち受けている全てのタスクを起動します。

このメソッドは notify() と同じように振る舞いますが、待ち受けている全てのタスクを起動します。

このメソッドが呼び出される前にロックを獲得しておかなければなりません。また、メソッド呼び出し後速やかにロックを解除しなければなりません。 解除された ロックとと共に呼び出された場合、 RuntimeError 例外が送出されます。

release()

下層のロックを解除します。

アンロック状態のロックに対して呼び出された場合、RuntimeError が送出されます。

coroutine wait()

通知を受けるまで待機します。

このメソッドが呼び出された時点で呼び出し元のタスクがロックを獲得していない場合、 RuntimeError 例外が送出されます。

このメソッドは下層のロックを解除し、その後 notify() または notify_all() の呼び出しによって起動されるまで処理をブロックします。いったん起動されると、 Condition は再びロックを獲得し、メソッドは True を返します。

coroutine wait_for(predicate)

引数 predicate の条件が になるまで待機します。

引数 predicate は戻り値が真偽地として解釈可能な呼び出し可能オブジェクトでなければなりません。 predicate の最終的な値が戻り値になります。

Semaphore

class asyncio.Semaphore(value=1, *, loop=None)

セマフォオブジェクトです。スレッドセーフではありません。

セマフォは内部のカウンターを管理しています。カウンターは acquire() メソッドの呼び出しによって減算され、 release() メソッドの呼び出しによって加算されます。カウンターがゼロを下回ることはありません。 acquire() メソッドが呼び出された時にカウンターがゼロになっていると、セマフォは処理をブロックし、他のタスクが release() メソッドを呼び出すまで待機します。

オプション引数 value は内部カウンターの初期値を与えます (デフォルトは 1 です)。 指定された値が 0 より小さい場合、 ValueError 例外が送出されます。

Deprecated since version 3.8, will be removed in version 3.10: loop パラメータ。

Semaphore 望ましい使用方法は、 async with 文と組み合わせて使うことです:

sem = asyncio.Semaphore(10)

# ... later
async with sem:
    # work with shared resource

これは以下のコードと等価です:

sem = asyncio.Semaphore(10)

# ... later
await sem.acquire()
try:
    # work with shared resource
finally:
    sem.release()
coroutine acquire()

セマフォを獲得します。

内部カウンターがゼロより大きい場合、カウンターを1つ減算して即座に True を返します。内部カウンターがゼロの場合、 release() が呼び出されるまで待機してから True を返します。

locked()

セマフォを直ちに獲得できない場合 True を返します。

release()

セマフォを解放し、内部カウンターを1つ加算します。セマフォ待ちをしているタスクを起動する可能性があります。

BoundedSemaphore と異なり、 Semaphorerelease()acquire() よりも多く呼び出すことを許容します。

BoundedSemaphore

class asyncio.BoundedSemaphore(value=1, *, loop=None)

有限セマフォオブジェクトです。スレッドセーフではありません。

有限セマフォは Semaphore の一種で、 release() メソッドの呼び出しにより内部カウンターが 初期値 よりも増加してしまう場合は ValueError 例外を送出します。

Deprecated since version 3.8, will be removed in version 3.10: loop パラメータ。


バージョン 3.9 で変更: await lockyield from lock およびそれらと with 文との組み合わせ (すなわち with await lockwith (yield from lock)) によるロックの獲得は削除されました。代わりに async with lock を使ってください。