Примитивы синхронизации

Исходный код: Lib/asyncio/locks.py


Примитивы синхронизации asyncio разработаны так, чтобы они были аналогичны примитивам модуля threading с двумя важными предостережения:

  • asyncio примитивы не являются потокобезопасной, поэтому их не следует используемый для синхронизации потоков ОС (для этого используйте threading);
  • методы из этих примитивов синхронизации не принимают аргумент timeout; используйте функцию asyncio.wait_for() для выполнения операций с таймаутами.

asyncio имеет следующие основные примитивы синхронизации:


Блокировки

class asyncio.Lock(*, loop=None)

Реализует блокировку mutex для asyncio задач. Не потокобезопасной.

Для обеспечения исключительного доступа к совместно используемому ресурсу можно asyncio используемый блокировку.

Предпочтительным способом использования блокировки является async with оператор:

lock = asyncio.Lock()

# ... позже
async with lock:
    # доступ к общему состоянию

Что эквивалентно:

lock = asyncio.Lock()

# ... позже
await lock.acquire()
try:
    # доступ к общему состоянию
finally:
    lock.release()

Deprecated since version 3.8, will be removed in version 3.10: Параметр loop.

coroutine acquire()

Установить блокировку.

Этот метод ждет, пока блокировка не unlocked, наборы он к locked и возвращаетs True.

Когда в acquire() блокируется более одного корутина, ожидающего разблокирования замка, в конечном счете продолжается только один корутин.

Приобретение замка - это fair: корутин, который идет, будет первым корутином, который начал ждать на замке.

release()

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

После locked блокировки Установить ее в unlocked и возвращает.

Если блокировка unlocked, то поднимается RuntimeError.

locked()

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

Событие

class asyncio.Event(*, loop=None)

Объект событий. Не потокобезопасной.

Событие asyncio может быть используемый для уведомления нескольких asyncio задач о том, что произошло какое-либо событие.

Объект Event управляет внутренним флагом, который может быть установлен в true с помощью метода set() и сброшен в false с помощью метода clear(). Метод 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():
    # Создайте объект Event.
    event = asyncio.Event()

    # Создать задачу, чтобы подождать, пока не будет установлено "событие2.
    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, если событие установлено.

Состояние

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

Объект условия. Не потокобезопасной.

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

По существу, объект Condition объединяет функциональные возможности Event и Lock. Возможно наличие нескольких объектов Condition совместно использующих один Lock, что позволяет координировать монопольный доступ к совместно используемому ресурсу между различными задачами, интересующими определенные состояниеs этого совместно используемого ресурса.

Необязательный аргумент lock должен быть объектом Lock или None. В последнем случае новый объект Lock создается автоматически.

Deprecated since version 3.8, will be removed in version 3.10: Параметр loop.

Предпочтительным способом использования условия является 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()

Получить основную блокировку.

Этот метод ожидает unlocked базовой блокировки, устанавливает ее в locked и возвращает True.

notify(n=1)

Не более n задач (по умолчанию 1), ожидающих выполнения этого условия. Если задачи не ожидаются, метод не выполняется.

блокировка должен быть получен до вызова этого метод и разблокирован вскоре после этого. При вызове с блокировкой unlocked возникает RuntimeError ошибка.

locked()

Возвращает True, будет ли получена соответствующая блокировка.

notify_all()

Пробуждение всех задач, ожидающих выполнения этого условия.

Этот метод действует как notify(), но просыпает все ожидающие задания.

Блокировка должен быть получен до вызова этого метод и разблокирован вскоре после этого. При вызове с блокировкой unlocked возникает RuntimeError ошибка.

release()

Разблокируйте основной блокировка.

При вызове при разблокированной блокировке возникает RuntimeError.

coroutine wait()

Жать, пока не зарегистрировано.

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

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

coroutine wait_for(predicate)

Додаться true predicate.

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

Семафор

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.

Предпочтительным способом использования семафора является async with оператор:

sem = asyncio.Semaphore(10)

# ... later
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().

BoundedSemaphore

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

Ограниченный семафорный объект. Не потокобезопасной.

Ограниченный семафор - версия Semaphore, поднимающая ValueError в release(), если она увеличивает внутренний счетчик выше начального value.

Deprecated since version 3.8, will be removed in version 3.10: Параметр loop.


Не рекомендуется, начиная с версии 3.7: Использование блокировки, используя await lock или yield from lock и/или with оператор (with await lock, with (yield from lock)) запрещено. Используйте async with lock вместо этого.