Документация Python неофициальный перевод
Содержание страницы

18.5.7. Примитивы синхронизацииSynchronization primitives

Блокировки:

Семафоры:

API блокировок asyncio разработан так, чтобы быть близким к классам модуля threading (Lock, Event, Condition, Semaphore, BoundedSemaphore), но не имеет параметра timeout. Функцию asyncio.wait_for() можно использовать для отмены задачи по таймауту.

18.5.7.1. БлокировкиLocks

18.5.7.1.1. БлокировкаLock

class asyncio.Lock(*, loop=None)

Объекты примитивных блокировок.

Примитивная блокировка – это примитив синхронизации, который не принадлежит конкретной корутине, когда заблокирован. Примитивная блокировка находится в одном из двух состояний: «locked» или «unlocked».

Он создаётся в разблокированном состоянии. У него есть два основных метода: acquire() и release(). Когда блокировка разблокирована, acquire() переводит её в заблокированное состояние и немедленно возвращается. Когда блокировка заблокирована, acquire() блокируется до тех пор, пока вызов release() в другой корутине не переведёт её в разблокированное состояние, после чего вызов acquire() снова устанавливает блокировку и возвращается. Метод release() должен вызываться только в заблокированном состоянии; он переводит блокировку в разблокированное состояние и немедленно завершается. При попытке освободить разблокированную блокировку будет возбуждено исключение RuntimeError.

Когда несколько корутин заблокированы в acquire() в ожидании перехода состояния в разблокированное, только одна корутина продолжает работу, когда вызов release() сбрасывает состояние в разблокированное; обрабатывается первая корутина, заблокированная в acquire().

acquire() является корутиной и должна вызываться через yield from.

Блокировки также поддерживают протокол менеджера контекста. Выражение (yield from lock) должно использоваться в качестве выражения менеджера контекста.

This class is не является потокобезопасным.

Использование:

lock = Lock()
...
yield from lock
try:
    ...
finally:
    lock.release()

Использование менеджера контекста:

lock = Lock()
...
with (yield from lock):
     ...

Объекты блокировки можно проверить на состояние блокировки:

if not lock.locked():
   yield from lock
else:
   # блокировка получена
    ...
locked()

Возвращает True, если блокировка захвачена.

coroutine acquire()

Захватить блокировку.

Этот метод блокируется до тех пор, пока блокировка не будет разблокирована, затем устанавливает её в заблокированное состояние и возвращает True.

Этот метод является корутиной.

release()

Освободить блокировку.

Когда блокировка заблокирована, сбросить её в разблокированное состояние и вернуться. Если какие-либо другие корутины заблокированы в ожидании разблокировки блокировки, позволить ровно одной из них продолжить.

При вызове на разблокированной блокировке возбуждается RuntimeError.

Возвращаемое значение отсутствует.

18.5.7.1.2. Event

class asyncio.Event(*, loop=None)

Реализация Event, асинхронный аналог threading.Event.

Класс, реализующий объекты событий. Событие управляет флагом, который можно установить в true с помощью метода set() и сбросить в false с помощью метода clear(). Метод wait() блокируется, пока флаг не станет true. Изначально флаг равен false.

This class is не является потокобезопасным.

clear()

Сбрасывает внутренний флаг в false. После этого корутины, вызывающие wait(), будут блокироваться, пока не будет вызван set(), чтобы снова установить внутренний флаг в true.

is_set()

Возвращает True тогда и только тогда, когда внутренний флаг равен true.

set()

Устанавливает внутренний флаг в true. Все корутины, ожидающие его установки в true, пробуждаются. Корутины, вызывающие wait() после того, как флаг уже true, не будут блокироваться вовсе.

coroutine wait()

Блокироваться до тех пор, пока внутренний флаг не станет true.

Если при входе внутренний флаг равен true, немедленно возвращает True. В противном случае блокируется до тех пор, пока другая корутина не вызовет set() для установки флага в true, после чего возвращает True.

Этот метод является корутиной.

18.5.7.1.3. Condition

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

Реализация Condition, асинхронный аналог threading.Condition.

Этот класс реализует объекты переменных условия. Переменная условия позволяет одной или нескольким корутинам ожидать, пока они не будут уведомлены другой корутиной.

Если передан аргумент блокировка и он не равен None, он должен быть объектом Блокировка, который используется в качестве нижележащей блокировки. В противном случае создаётся новый объект Блокировка и используется как нижележащая блокировка.

This class is не является потокобезопасным.

coroutine acquire()

Захватывает базовую блокировку.

Этот метод блокируется, пока блокировка не будет освобождена, затем захватывает её и возвращает True.

Этот метод является корутиной.

notify(n=1)

По умолчанию пробуждает одну корутину, ожидающую на этом условии (если такая есть). Если вызывающая корутина не захватила блокировку на момент вызова этого метода, возбуждается RuntimeError.

Этот метод пробуждает не более n корутин, ожидающих переменную условия; он ничего не делает, если никакие корутины не ожидают.

Примечание

Пробуждённая корутина на самом деле не возвращается из вызова wait(), пока не сможет повторно захватить блокировку. Поскольку notify() не освобождает блокировку, это должен сделать её вызывающий код.

locked()

Возвращает True, если нижележащая блокировка захвачена.

notify_all()

Пробуждает все корутины, ожидающие на этом условии. Этот метод действует как notify(), но пробуждает все ожидающие корутины, а не одну. Если вызывающая корутина не захватила блокировку на момент вызова этого метода, возбуждается RuntimeError.

release()

Освобождает базовую блокировку.

Когда блокировка заблокирована, сбросить её в разблокированное состояние и вернуться. Если какие-либо другие корутины заблокированы в ожидании разблокировки блокировки, разрешить ровно одной из них продолжить выполнение.

При вызове на незахваченной блокировке возбуждается RuntimeError.

Возвращаемое значение отсутствует.

coroutine wait()

Ожидает уведомления.

Если вызывающая корутина не захватила блокировку на момент вызова этого метода, возбуждается RuntimeError.

Этот метод освобождает нижележащую блокировку, а затем блокируется, пока не будет пробуждён вызовом notify() или notify_all() на той же переменной условия в другой корутине. После пробуждения он повторно захватывает блокировку и возвращает True.

Этот метод является корутиной.

coroutine wait_for(predicate)

Ожидает, пока предикат не станет истинным.

Предикат должен быть вызываемым объектом, результат которого будет интерпретироваться как логическое значение. Итоговое значение предиката является возвращаемым значением.

Этот метод является корутиной.

18.5.7.2. СемафорыSemaphores

18.5.7.2.1. Semaphore

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

Реализация семафора.

Семафор управляет внутренним счётчиком, который уменьшается при каждом вызове acquire() и увеличивается при каждом вызове release(). Счётчик никогда не может стать отрицательным; когда acquire() обнаруживает, что он равен нулю, он блокируется, ожидая, пока другая корутина вызовет release().

Семафоры также поддерживают протокол управления контекстом.

Необязательный аргумент задаёт начальное значение внутреннего счётчика; по умолчанию оно равно 1. Если переданное значение меньше 0, возбуждается ValueError.

This class is не является потокобезопасным.

coroutine acquire()

Захватывает семафор.

Если при входе внутренний счётчик больше нуля, уменьшить его на единицу и сразу вернуть True. Если он равен нулю при входе, заблокироваться, ожидая, пока другая корутина вызовет release(), чтобы сделать его больше 0, а затем вернуть True.

Этот метод является корутиной.

locked()

Возвращает True, если семафор не может быть захвачен немедленно.

release()

Освободить семафор, увеличивая внутренний счётчик на единицу. Если он был равен нулю на входе и другая корутина ожидает, пока он снова станет больше нуля, пробудить эту корутину.

18.5.7.2.2. BoundedSemaphore

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

Реализация ограниченного семафора. Наследует от Semaphore.

Это возбуждает ValueError в release(), если это приведёт к увеличению значения выше начального.