Содержание страницы
Примитивы синхронизации¶Synchronization Primitives
Исходный код: Lib/asyncio/locks.py
Примитивы синхронизации asyncio устроены аналогично примитивам модуля threading, но с двумя важными оговорками:
Примитивы asyncio не являются потокобезопасными, поэтому их не следует использовать для синхронизации потоков ОС (для этого используйте
threading);Методы этих примитивов синхронизации не принимают аргумент timeout; для выполнения операций с таймаутами используйте функцию
asyncio.wait_for().
В asyncio имеются следующие базовые примитивы синхронизации:
Блокировка¶Lock
-
class
asyncio.Lock(*, loop=None)¶ Реализует блокировку мьютекса для задач asyncio. Не потокобезопасна.
Блокировка asyncio может использоваться для обеспечения исключительного доступа к общему ресурсу.
The preferred way to use a Lock is an
async withstatement:lock = asyncio.Lock() # ... позже async with lock: # доступ к общему состоянию
это эквивалентно следующему:
lock = asyncio.Lock() # ... позже await lock.acquire() try: # доступ к общему состоянию finally: lock.release()
Устарело с версии 3.8, будет удалено в версии 3.10: Параметр loop.
-
coroutine
acquire()¶ Захватывает блокировку.
Этот метод ожидает, пока блокировка не будет разблокирована, переводит её в состояние заблокирована и возвращает
True.Если несколько корутин заблокированы вызовом
acquire()в ожидании разблокировки блокировки, только одна из них в итоге продолжит выполнение.Захват блокировки справедлив: выполнение продолжит первая корутина, начавшая ожидание блокировки.
-
release()¶ Освобождает блокировку.
Если блокировка заблокирована, сбрасывает её в состояние разблокирована и завершается.
Если блокировка разблокирована, возбуждается исключение
RuntimeError.
-
locked()¶ Возвращает
True, если блокировка заблокирована.
-
coroutine
Event¶
-
class
asyncio.Event(*, loop=None)¶ Объект события. Не потокобезопасен.
Событие asyncio может использоваться для оповещения нескольких задач asyncio о наступлении некоторого события.
Объект Event управляет внутренним флагом, который может быть установлен в true методом
set()и сброшен в false методомclear(). Методwait()блокируется, пока флаг не будет установлен в true. Изначально флаг установлен в false.Устарело с версии 3.8, будет удалено в версии 3.10: Параметр loop.
Пример:
async def waiter(event): print('waiting for it ...') await event.wait() print('... got it!') async def main(): # Создать объект Event. event = asyncio.Event() # Создать задачу, ожидающую установки 'event'. waiter_task = asyncio.create_task(waiter(event)) # Подождать 1 секунду и установить событие. await asyncio.sleep(1) event.set() # Дождаться завершения ожидающей задачи. await waiter_task asyncio.run(main())
-
coroutine
wait()¶ Ожидает, пока событие не будет установлено.
Если событие установлено, немедленно возвращает
True. В противном случае блокируется до тех пор, пока другая задача не вызоветset().
-
set()¶ Устанавливает событие.
Все задачи, ожидающие установки события, будут немедленно пробуждены.
-
clear()¶ Сбрасывает (снимает) событие.
Задачи, ожидающие на
wait(), теперь будут блокироваться, пока методset()не будет вызван снова.
-
is_set()¶ Возвращает
True, если событие установлено.
-
coroutine
Condition¶
-
class
asyncio.Condition(lock=None, *, loop=None)¶ Объект Condition. Не потокобезопасен.
Примитив условия asyncio позволяет задаче дождаться наступления некоторого события, а затем получить исключительный доступ к общему ресурсу.
По сути, объект Condition объединяет функциональность
EventиLock. Несколько объектов Condition могут совместно использовать одну блокировку, что позволяет координировать исключительный доступ к общему ресурсу между различными задачами, заинтересованными в определённых состояниях этого ресурса.Необязательный аргумент блокировка должен быть объектом
LockилиNone. В последнем случае новый объект блокировки создаётся автоматически.Устарело с версии 3.8, будет удалено в версии 3.10: Параметр loop.
Предпочтительный способ использования Condition – оператор
async with:cond = asyncio.Condition() # ... позже async with cond: await cond.wait()
это эквивалентно следующему:
cond = asyncio.Condition() # ... позже 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
Semaphore¶
-
class
asyncio.Semaphore(value=1, *, loop=None)¶ Объект семафора. Не потокобезопасен.
Семафор управляет внутренним счётчиком, который уменьшается при каждом вызове
acquire()и увеличивается при каждом вызовеrelease(). Счётчик никогда не может стать меньше нуля; когдаacquire()обнаруживает, что он равен нулю, он блокируется в ожидании, пока какая-либо задача не вызоветrelease().Необязательный аргумент value задаёт начальное значение внутреннего счётчика (по умолчанию
1). Если переданное значение меньше0, возникаетValueError.Устарело с версии 3.8, будет удалено в версии 3.10: Параметр loop.
Предпочтительный способ использования семафора – оператор
async with:sem = asyncio.Semaphore(10) # ... позже async with sem: # работать с общим ресурсом
это эквивалентно следующему:
sem = asyncio.Semaphore(10) # ... позже await sem.acquire() try: # работать с общим ресурсом finally: sem.release()
-
coroutine
acquire()¶ Захватывает семафор.
Если внутренний счётчик больше нуля, уменьшить его на единицу и немедленно вернуть
True. Если он равен нулю, ждать, пока не будет вызванrelease(), и вернутьTrue.
-
locked()¶ Возвращает
True, если семафор не может быть захвачен немедленно.
-
release()¶ Освобождает семафор, увеличивая внутренний счётчик на единицу. Может пробудить задачу, ожидающую захвата семафора.
В отличие от
BoundedSemaphore,Semaphoreдопускает больше вызововrelease(), чем вызововacquire().
-
coroutine
BoundedSemaphore¶
-
class
asyncio.BoundedSemaphore(value=1, *, loop=None)¶ Объект ограниченного семафора. Не потокобезопасен.
Bounded Semaphore – это версия
Semaphore, которая возбуждаетValueErrorвrelease(), если увеличивает внутренний счётчик выше начального value.Устарело с версии 3.8, будет удалено в версии 3.10: Параметр loop.
Устарело с версии 3.7: Получение блокировки с помощью await lock или yield from lock и/или
with (with await lock, with (yield from
lock)) устарело. Вместо этого используйте async with lock.