asyncio-sync.md
1> **Источник:** https://python-all.ru/3.9/library/asyncio-sync.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Примитивы синхронизации89**Исходный код:** [Lib/asyncio/locks.py](https://python-all.ru/src/3.9/Lib/asyncio/locks.py)1011---1213Примитивы синхронизации asyncio устроены аналогично примитивам модуля [`threading`](https://python-all.ru/3.9/library/threading.html#module-threading), но с двумя важными оговорками:1415- Примитивы asyncio не являются потокобезопасными, поэтому их не следует использовать для синхронизации потоков ОС (для этого используйте [`threading`](https://python-all.ru/3.9/library/threading.html#module-threading));16- Методы этих примитивов синхронизации не принимают аргумент *timeout*; для выполнения операций с таймаутами используйте функцию [`asyncio.wait_for()`](https://python-all.ru/3.9/library/asyncio-task.html#asyncio.wait_for).1718В asyncio имеются следующие базовые примитивы синхронизации:1920- [`Lock`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Lock)21- [`Event`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Event)22- [`Condition`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Condition)23- [`Semaphore`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Semaphore)24- [`BoundedSemaphore`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.BoundedSemaphore)2526---2728## Блокировка2930#### `class asyncio.Lock(*, loop=None)`3132Реализует блокировку мьютекса для задач asyncio. Не потокобезопасна.3334Блокировка asyncio может использоваться для обеспечения исключительного доступа к общему ресурсу.3536The preferred way to use a Lock is an [`async with`](https://python-all.ru/3.9/reference/compound_stmts.html#async-with) statement:3738```python39lock = asyncio.Lock()4041# ... позже42async with lock:43 # доступ к общему состоянию44```4546это эквивалентно следующему:4748```python49lock = asyncio.Lock()5051# ... позже52await lock.acquire()53try:54 # доступ к общему состоянию55finally:56 lock.release()57```5859Устарело с версии 3.8, будет удалено в версии 3.10: Параметр *loop*.6061#### `coroutine acquire()`6263Захватывает блокировку.6465Этот метод ожидает, пока блокировка не будет *разблокирована*, переводит её в состояние *заблокирована* и возвращает `True`.6667Если несколько корутин заблокированы вызовом [`acquire()`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Lock.acquire) в ожидании разблокировки блокировки, только одна из них в итоге продолжит выполнение.6869Захват блокировки *справедлив*: выполнение продолжит первая корутина, начавшая ожидание блокировки.7071#### `release()`7273Освобождает блокировку.7475Если блокировка *заблокирована*, сбрасывает её в состояние *разблокирована* и завершается.7677Если блокировка *разблокирована*, возбуждается исключение [`RuntimeError`](https://python-all.ru/3.9/library/exceptions.html#RuntimeError).7879#### `locked()`8081Возвращает `True`, если блокировка *заблокирована*.8283## Event8485#### `class asyncio.Event(*, loop=None)`8687Объект события. Не потокобезопасен.8889Событие asyncio может использоваться для оповещения нескольких задач asyncio о наступлении некоторого события.9091Объект Event управляет внутренним флагом, который может быть установлен в *true* методом [`set()`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Event.set) и сброшен в *false* методом [`clear()`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Event.clear). Метод [`wait()`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Event.wait) блокируется, пока флаг не будет установлен в *true*. Изначально флаг установлен в *false*.9293Устарело с версии 3.8, будет удалено в версии 3.10: Параметр *loop*.9495Пример:9697```python98async def waiter(event):99 print('waiting for it ...')100 await event.wait()101 print('... got it!')102103async def main():104 # Создать объект Event.105 event = asyncio.Event()106107 # Создать задачу, ожидающую установки 'event'.108 waiter_task = asyncio.create_task(waiter(event))109110 # Подождать 1 секунду и установить событие.111 await asyncio.sleep(1)112 event.set()113114 # Дождаться завершения ожидающей задачи.115 await waiter_task116117asyncio.run(main())118```119120#### `coroutine wait()`121122Ожидает, пока событие не будет установлено.123124Если событие установлено, немедленно возвращает `True`. В противном случае блокируется до тех пор, пока другая задача не вызовет [`set()`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Event.set).125126#### `set()`127128Устанавливает событие.129130Все задачи, ожидающие установки события, будут немедленно пробуждены.131132#### `clear()`133134Сбрасывает (снимает) событие.135136Задачи, ожидающие на [`wait()`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Event.wait), теперь будут блокироваться, пока метод [`set()`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Event.set) не будет вызван снова.137138#### `is_set()`139140Возвращает `True`, если событие установлено.141142## Condition143144#### `class asyncio.Condition(lock=None, *, loop=None)`145146Объект Condition. Не потокобезопасен.147148Примитив условия asyncio позволяет задаче дождаться наступления некоторого события, а затем получить исключительный доступ к общему ресурсу.149150По сути, объект Condition объединяет функциональность [`Event`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Event) и [`Lock`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Lock). Несколько объектов Condition могут совместно использовать одну блокировку, что позволяет координировать исключительный доступ к общему ресурсу между различными задачами, заинтересованными в определённых состояниях этого ресурса.151152Необязательный аргумент *блокировка* должен быть объектом [`Lock`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Lock) или `None`. В последнем случае новый объект блокировки создаётся автоматически.153154Устарело с версии 3.8, будет удалено в версии 3.10: Параметр *loop*.155156Предпочтительный способ использования Condition – оператор [`async with`](https://python-all.ru/3.9/reference/compound_stmts.html#async-with):157158```python159cond = asyncio.Condition()160161# ... позже162async with cond:163 await cond.wait()164```165166это эквивалентно следующему:167168```python169cond = asyncio.Condition()170171# ... позже172await cond.acquire()173try:174 await cond.wait()175finally:176 cond.release()177```178179#### `coroutine acquire()`180181Захватывает базовую блокировку.182183Этот метод ожидает, пока базовая блокировка не будет *разблокирована*, устанавливает её в состояние *заблокирована* и возвращает `True`.184185#### `notify(n=1)`186187Будит не более *n* задач (по умолчанию 1), ожидающих на этом условии. Если ожидающих задач нет, метод ничего не делает.188189Блокировка должна быть захвачена до вызова этого метода и освобождена сразу после. Если вызвать с *разблокированной* блокировкой, будет возбуждено исключение [`RuntimeError`](https://python-all.ru/3.9/library/exceptions.html#RuntimeError).190191#### `locked()`192193Возвращает `True`, если базовая блокировка захвачена.194195#### `notify_all()`196197Пробуждает все задачи, ожидающие данное условие.198199Этот метод действует как [`notify()`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Condition.notify), но пробуждает все ожидающие задачи.200201Блокировка должна быть захвачена до вызова этого метода и освобождена сразу после. Если вызвать с *разблокированной* блокировкой, будет возбуждено исключение [`RuntimeError`](https://python-all.ru/3.9/library/exceptions.html#RuntimeError).202203#### `release()`204205Освобождает базовую блокировку.206207При вызове на незаблокированной блокировке возникает [`RuntimeError`](https://python-all.ru/3.9/library/exceptions.html#RuntimeError).208209#### `coroutine wait()`210211Ожидает уведомления.212213Если вызывающая задача не захватила блокировку на момент вызова этого метода, возникает [`RuntimeError`](https://python-all.ru/3.9/library/exceptions.html#RuntimeError).214215Этот метод освобождает базовую блокировку и блокируется до тех пор, пока не будет пробуждён вызовом [`notify()`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Condition.notify) или [`notify_all()`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Condition.notify_all). После пробуждения условие снова захватывает свою блокировку, и метод возвращает `True`.216217#### `coroutine wait_for(predicate)`218219Ожидает, пока предикат не станет *истинным*.220221Предикат должен быть вызываемым объектом, результат которого будет интерпретирован как булево значение. Конечное значение – это возвращаемое значение.222223## Semaphore224225#### `class asyncio.Semaphore(value=1, *, loop=None)`226227Объект семафора. Не потокобезопасен.228229Семафор управляет внутренним счётчиком, который уменьшается при каждом вызове [`acquire()`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Semaphore.acquire) и увеличивается при каждом вызове [`release()`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Semaphore.release). Счётчик никогда не может стать меньше нуля; когда [`acquire()`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Semaphore.acquire) обнаруживает, что он равен нулю, он блокируется в ожидании, пока какая-либо задача не вызовет [`release()`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Semaphore.release).230231Необязательный аргумент *value* задаёт начальное значение внутреннего счётчика (по умолчанию `1`). Если переданное значение меньше `0`, возникает [`ValueError`](https://python-all.ru/3.9/library/exceptions.html#ValueError).232233Устарело с версии 3.8, будет удалено в версии 3.10: Параметр *loop*.234235Предпочтительный способ использования семафора – оператор [`async with`](https://python-all.ru/3.9/reference/compound_stmts.html#async-with):236237```python238sem = asyncio.Semaphore(10)239240# ... позже241async with sem:242 # работать с общим ресурсом243```244245это эквивалентно следующему:246247```python248sem = asyncio.Semaphore(10)249250# ... позже251await sem.acquire()252try:253 # работать с общим ресурсом254finally:255 sem.release()256```257258#### `coroutine acquire()`259260Захватывает семафор.261262Если внутренний счётчик больше нуля, уменьшить его на единицу и немедленно вернуть `True`. Если он равен нулю, ждать, пока не будет вызван [`release()`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Semaphore.release), и вернуть `True`.263264#### `locked()`265266Возвращает `True`, если семафор не может быть захвачен немедленно.267268#### `release()`269270Освобождает семафор, увеличивая внутренний счётчик на единицу. Может пробудить задачу, ожидающую захвата семафора.271272В отличие от [`BoundedSemaphore`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.BoundedSemaphore), [`Semaphore`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Semaphore) допускает больше вызовов `release()`, чем вызовов `acquire()`.273274## BoundedSemaphore275276#### `class asyncio.BoundedSemaphore(value=1, *, loop=None)`277278Объект ограниченного семафора. Не потокобезопасен.279280Bounded Semaphore – это версия [`Semaphore`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Semaphore), которая возбуждает [`ValueError`](https://python-all.ru/3.9/library/exceptions.html#ValueError) в [`release()`](https://python-all.ru/3.9/library/asyncio-sync.html#asyncio.Semaphore.release), если увеличивает внутренний счётчик выше начального *value*.281282Устарело с версии 3.8, будет удалено в версии 3.10: Параметр *loop*.283284---285286Изменено в версии 3.9: Захват блокировки с помощью `await lock` или `yield from lock` и/или оператора [`with`](https://python-all.ru/3.9/reference/compound_stmts.html#with) (`with await lock`, `with (yield from lock)`) был удалён. Вместо этого используйте `async with lock`.287