Примитивы синхронизации
Исходный код: Lib/asyncio/locks.py
Примитивы синхронизации asyncio разработаны с целью быть похожими на примитивы модуля threading с двумя важными оговорками:
- Примитивы asyncio не являются потокобезопасными, поэтому их не следует использовать для синхронизации потоков ОС (для этого используйте
threading); - методы этих примитивов синхронизации не принимают аргумент timeout; используйте функцию
asyncio.wait_for()для выполнения операций с таймаутами.
asyncio предоставляет следующие основные примитивы синхронизации:
Блокировка
-
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если блокировка заблокирована.
-
Событие
-
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если событие установлено.
-
Условие
-
class asyncio.Condition(lock=None) -
Объект условия. Не потокобезопасен.
Примитив asyncio условия может использоваться задачей для ожидания события и последующего получения эксклюзивного доступа к общему ресурсу.
По сути, объект условия объединяет функциональность объекта
Eventи объектаLock. Возможна ситуация, когда несколько объектов Condition используют одну блокировку, что позволяет координировать эксклюзивный доступ к общему ресурсу между разными задачами, заинтересованными в определённых состояниях этого ресурса.Необязательный аргумент 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), ожидающих этого условия. Если ждёт меньше n задач, они все разбужатся.
Блокировка должна быть получена перед вызовом этого метода и освобождена вскоре после него. Если вызван с разблокированной блокировкой, генерируется ошибка
RuntimeError.
-
locked() -
Возвращает
Trueесли основная блокировка получена.
-
notify_all() -
Разбудить все задачи, ожидающие этого условия.
Этот метод работает как
notify(), но разбуживает все ожидающие задачи.Блокировка должна быть получена перед вызовом этого метода и освобождена вскоре после него. Если вызван с разблокированной блокировкой, генерируется ошибка
RuntimeError.
-
release() -
Освободить основную блокировку.
При вызове на разблокированной блокировке возникает ошибка
RuntimeError.
-
coroutine wait() -
Ожидать уведомления.
Если вызывающая задача не получила блокировку при вызове этого метода, генерируется ошибка
RuntimeError.Этот метод освобождает основную блокировку, а затем блокирует выполнение, пока его не разбудят с помощью вызова
notify()илиnotify_all(). После разбуждения Condition вновь получает свою блокировку, и этот метод возвращаетTrue.Обратите внимание, что задача может вернуться из этого вызова преждевременно, поэтому вызывающий код должен всегда повторно проверять состояние и быть готовым к повторному вызову
wait(). По этой причине предпочтительнее использоватьwait_for()вместо этого.
-
coroutine wait_for(predicate) -
Ожидать, пока предикат станет true.
Предикат должен быть вызываемым объектом, результат которого будет интерпретироваться как булево значение. Метод будет повторять
wait()до тех пор, пока предикат не примет значение 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.13/library/asyncio-sync.html