Примитивы синхронизации¶
Исходный код: 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
.