Примитивы синхронизации
Исходный код: Lib/asyncio/locks.py
Примитивы синхронизации asyncio разработаны по аналогии с примитивами модуля threading с двумя важными оговорками:
- Примитивы asyncio не потокобезопасны, поэтому их не следует использовать для синхронизации задач ОС (для этого используйте
threading); - методы этих примитивов синхронизации не принимают аргумент timeout; для выполнения операций с таймаутами используйте функцию
asyncio.wait_for().
asyncio предоставляет следующие базовые примитивы синхронизации:
Блокировка (Lock)
-
class asyncio.Lock -
Реализует мьютекс-блокировку для задач asyncio. Не потокобезопасна.
Блокировка asyncio может использоваться для обеспечения исключительного доступа к общему ресурсу.
Предпочтительный способ использования Lock — это оператор
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, если блокировка заблокирована.
-
Событие (Event)
-
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, если событие установлено.
-
Условие (Condition)
-
class asyncio.Condition(lock=None) -
Объект условия. Не потокобезопасен.
Примитив asyncio условия может использоваться задачей для ожидания наступления события и последующего получения исключительного доступа к общему ресурсу.
По сути, объект Condition объединяет функциональность объекта
Eventи объектаLock. Можно иметь несколько объектов Condition, использующих одну блокировку, что позволяет координировать исключительный доступ к общему ресурсу между различными задачами, заинтересованными в определенных состояниях этого общего ресурса.Необязательный аргумент lock должен быть объектом
LockилиNone. В последнем случае объект Lock создаётся автоматически.Изменено в версии 3.10: Параметр loop удалён.
Предпочтительный способ использования Condition — это оператор
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(). После пробуждения Condition снова получает свою блокировку, и этот метод возвращаетTrue.
-
coroutine wait_for(predicate) -
Ожидать, пока предикат не станет true.
Предикат должен быть вызываемым объектом, результат которого будет интерпретироваться как булево значение. Конечное значение — это возвращаемое значение.
-
Семафор
-
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().
-
Ограниченный семафор
-
class asyncio.BoundedSemaphore(value=1) -
Объект ограниченного семафора. Не потокобезопасен.
Ограниченный семафор — это версия
Semaphore, которая выбросит исключениеValueErrorвrelease(), если она увеличивает внутренний счётчик выше начального значения value.Изменено в версии 3.10: Параметр loop удалён.
Барьер
-
class asyncio.Barrier(parties) -
Объект барьера. Не потокобезопасен.
Барьер — простая синхронизирующая примитива, которая позволяет заблокироваться, пока parties задач не дождутся его. Задачи могут ожидать метода
wait(), и они будут заблокированы, пока указанное количество задач не дождётсяwait(). В этот момент все ожидающие задачи разблокируются одновременно.Можно использовать
async withкак альтернативу ожиданиюwait().Барьер может быть использован любое количество раз.
Пример:
async def example_barrier(): # barrier with 3 parties b = asyncio.Barrier(3) # create 2 new waiting tasks asyncio.create_task(b.wait()) asyncio.create_task(b.wait()) await asyncio.sleep(0) print(b) # The third .wait() call passes the barrier await b.wait() print(b) print("barrier passed") await asyncio.sleep(0) print(b) asyncio.run(example_barrier())Результат этого примера:
<asyncio.locks.Barrier object at 0x... [filling, waiters:2/3]> <asyncio.locks.Barrier object at 0x... [draining, waiters:0/3]> barrier passed <asyncio.locks.Barrier object at 0x... [filling, waiters:0/3]>
Добавлен в версии 3.11.
-
coroutine wait() -
Проход через барьер. Когда все задачи, участвующие в барьере, вызовут эту функцию, все они разблокируются одновременно.
Когда ожидающая или заблокированная задача в барьере отменяется, эта задача выходит из барьера, который остаётся в том же состоянии. Если состояние барьера «заполнение», количество ожидающих задач уменьшается на 1.
Возвращаемое значение — целое число в диапазоне от 0 до
parties-1, разное для каждой задачи. Это можно использовать для выбора задачи, чтобы выполнить некоторую специальную обработку, например:... async with barrier as position: if position == 0: # Only one task prints this print('End of *draining phase*')Этот метод может выбросить исключение
BrokenBarrierError, если барьер сломан или сброшен, пока задача ждёт. Может выброситьCancelledError, если задача отменена.
-
coroutine reset() -
Возвращение барьера в исходное, пустое состояние. Любые задачи, ожидающие его, получат исключение
BrokenBarrierError.Если барьер сломан, лучше просто оставить его и создать новый.
-
coroutine abort() -
Переводит барьер в состояние «сломан». Это заставляет любые активные или будущие вызовы
wait()завершиться с исключениемBrokenBarrierError. Используйте это, например, если одна из задач должна прерваться, чтобы избежать бесконечного ожидания задач.
-
parties -
Количество задач, необходимых для прохождения барьера.
-
n_waiting -
Количество задач, в настоящее время ожидающих в барьере во время заполнения.
-
broken -
Булево значение, которое равно
Trueесли барьер в состоянии «сломан».
-
-
exception asyncio.BrokenBarrierError -
Это исключение, подкласс
RuntimeError, генерируется, когда объектBarrierсбрасывается или разрывается.
Изменено в версии 3.9: Приобретение блокировки с помощью await lock или yield from lock и/или инструкции with (with await lock, with (yield from
lock)) было удалено. Используйте async with lock вместо этого.
© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/library/asyncio-sync.html