Примитивы синхронизации¶
Исходный код: Lib/asyncio/locks.py.
Примитивы синхронизации asyncio разработаны так, чтобы быть похожими на примитивы модуля threading с двумя важными оговорками:
Примитивы asyncio не являются потокобезопасными, поэтому их не следует использовать для синхронизации потоков ОС (для этого используйте
threading);методы этих примитивов синхронизации не принимают аргумент timeout; для выполнения операций с таймаутами используйте функцию
asyncio.wait_for().
asyncio имеет следующие основные примитивы синхронизации:
Замок¶
-
class
asyncio.Lock¶ Реализует мьютексную блокировку для задач asyncio. Не является потокобезопасным.
Блокировка asyncio может быть использована для обеспечения эксклюзивного доступа к общему ресурсу.
Предпочтительным способом использования блокировки является оператор
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()
Изменено в версии 3.10: Удален параметр loop.
-
coroutine
acquire()¶ Приобретите замок.
Этот метод ждет, пока блокировка не будет разблокирована, устанавливает ее в заблокирована и возвращает
True.Когда несколько программ блокируются в
acquire()в ожидании разблокировки блокировки, в конечном итоге выполняется только одна программа.Получение блокировки является справедливым: выполняемая программа будет первой программой, которая начала ожидать блокировку.
-
release()¶ Освободите замок.
Когда замок заблокирован, сбросьте его на разблокирован и вернитесь.
Если блокировка разблокирована, возникает ошибка
RuntimeError.
-
locked()¶ Возвращает
True, если замок заблокирован.
-
coroutine
Событие¶
-
class
asyncio.Event¶ Объект события. Не является потокобезопасным.
Событие asyncio можно использовать для уведомления нескольких задач asyncio о том, что произошло какое-то событие.
Объект Event управляет внутренним флагом, который может быть установлен в значение true методом
set()и сброшен в значение false методомclear(). Методwait()блокируется до тех пор, пока флаг не будет установлен в значение true. Изначально флаг устанавливается в false.Изменено в версии 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, если событие установлено.
-
coroutine
Состояние¶
-
class
asyncio.Condition(lock=None)¶ Объект Condition. Не является потокобезопасным.
Примитив условия asyncio может быть использован задачей для ожидания некоторого события и последующего получения эксклюзивного доступа к общему ресурсу.
По сути, объект Condition сочетает в себе функциональность
EventиLock. Возможно, чтобы несколько объектов Condition совместно использовали один Lock, что позволяет координировать эксклюзивный доступ к общему ресурсу между различными задачами, заинтересованными в определенных состояниях этого общего ресурса.Необязательный аргумент lock должен быть объектом
LockилиNone. В последнем случае новый объект Lock создается автоматически.Изменено в версии 3.10: Удален параметр loop.
Предпочтительным способом использования условия является оператор
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 задач (по умолчанию 1), ожидающих выполнения данного условия. Метод не работает, если ни одна задача не ожидает.
Блокировка должна быть получена до вызова этого метода и освобождена вскоре после него. Если метод вызывается с незаблокированной блокировкой, будет выдана ошибка
RuntimeError.
-
locked()¶ Возвращает
True, если базовая блокировка получена.
-
notify_all()¶ Разбудите все задачи, ожидающие этого условия.
Этот метод действует аналогично
notify(), но пробуждает все ожидающие задачи.Блокировка должна быть получена до вызова этого метода и освобождена вскоре после него. Если метод вызывается с незаблокированной блокировкой, будет выдана ошибка
RuntimeError.
-
release()¶ Освободите основную блокировку.
При вызове на разблокированной блокировке возникает ошибка
RuntimeError.
-
coroutine
wait()¶ Дождитесь уведомления.
Если вызывающая задача не получила блокировку на момент вызова этого метода, будет вызвана ошибка
RuntimeError.Этот метод освобождает основную блокировку, а затем блокирует ее до тех пор, пока она не будет разбужена вызовом
notify()илиnotify_all(). После пробуждения условие вновь приобретает свою блокировку, и этот метод возвращаетTrue.
-
coroutine
wait_for(predicate)¶ Подождите, пока предикат станет истинным.
Предикат должен быть вызываемой переменной, результат которой будет интерпретирован как булево значение. Конечное значение - это возвращаемое значение.
-
coroutine
Семафор¶
-
class
asyncio.Semaphore(value=1)¶ Объект семафора. Не является потокобезопасным.
Семафор управляет внутренним счетчиком, который уменьшается при каждом вызове
acquire()и увеличивается при каждом вызовеrelease(). Счетчик никогда не может опуститься ниже нуля; когдаacquire()обнаруживает, что он равен нулю, он блокируется, ожидая, пока какая-нибудь задача не вызоветrelease().Необязательный аргумент value задает начальное значение для внутреннего счетчика (по умолчанию
1). Если заданное значение меньше, чем0, то возникает ошибкаValueError.Изменено в версии 3.10: Удален параметр loop.
Предпочтительным способом использования семафора является оператор
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()¶ Приобретите семафор.
Если внутренний счетчик больше нуля, уменьшите его на единицу и немедленно верните
True. Если он равен нулю, дождитесь вызоваrelease()и вернитеTrue.
-
locked()¶ Возвращает
True, если семафор не может быть получен немедленно.
-
release()¶ Освобождает семафор, увеличивая внутренний счетчик на единицу. Может разбудить задачу, ожидающую получения семафора.
В отличие от
BoundedSemaphore,Semaphoreпозволяет делать больше вызововrelease(), чем вызововacquire().
-
coroutine
BoundedSemaphore¶
-
class
asyncio.BoundedSemaphore(value=1)¶ Ограниченный объект семафора. Не является потокобезопасным.
Bounded Semaphore - это версия
Semaphore, которая поднимаетValueErrorвrelease(), если увеличивает внутренний счетчик выше начального значения.Изменено в версии 3.10: Удален параметр loop.
Изменено в версии 3.9: Приобретение блокировки с помощью оператора await lock или yield from lock и/или with (with await lock, with (yield from lock)) было удалено. Вместо этого используйте async with lock.