Примитивы синхронизации
Исходный код: 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. В последнем случае объект блокировки создаётся автоматически.Изменено в версии 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), ожидающих этого условия. Метод является пустой операцией, если задач нет.
Блокировка должна быть захвачена перед вызовом этого метода и освобождена вскоре после него. При вызове с разблокированной блокировкой генерируется ошибка
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 удалён.
Изменено в версии 3.9: Захват блокировки с помощью await lock или yield from lock и/или оператора with (with await lock, with (yield from
lock)) был удалён. Используйте async with lock вместо этого.
© 2001–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.10/library/asyncio-sync.html