Документация Python неофициальный перевод

threading.md

584 строк · 74.5 КБ · обычная страница · сырой текст · скачать

1> **Источник:** https://python-all.ru/3.3/library/threading.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# 17.1. [`threading`](https://python-all.ru/3.3/library/threading.html#module-threading) – Потоковый параллелизм89**Исходный код:** [Lib/threading.py](https://python-all.ru/src/3.3/Lib/threading.py)1011---1213Этот модуль предоставляет интерфейсы threading более высокого уровня поверх низкоуровневого модуля [`_thread`](https://python-all.ru/3.3/library/_thread.html#module-_thread). Смотрите также модуль [`queue`](https://python-all.ru/3.3/library/queue.html#module-queue).1415Модуль [`dummy_threading`](https://python-all.ru/3.3/library/dummy_threading.html#module-dummy_threading) предназначен для ситуаций, когда [`threading`](https://python-all.ru/3.3/library/threading.html#module-threading) не может использоваться, поскольку [`_thread`](https://python-all.ru/3.3/library/_thread.html#module-_thread) отсутствует.1617> **Примечание**18>19> Хотя они не перечислены ниже, имена в стиле `camelCase`, использовавшиеся для некоторых методов и функций в этом модуле в серии Python 2.x, по-прежнему поддерживаются этим модулем.2021Этот модуль определяет следующие функции:2223#### `threading.active_count()`2425Возвращает количество объектов [`Thread`](https://python-all.ru/3.3/library/threading.html#threading.Thread), которые в данный момент активны. Возвращаемое количество равно длине списка, возвращаемого [`enumerate()`](https://python-all.ru/3.3/library/threading.html#threading.enumerate).2627#### `threading.current_thread()`2829Возвращает текущий объект [`Thread`](https://python-all.ru/3.3/library/threading.html#threading.Thread), соответствующий потоку управления вызывающего кода. Если поток управления вызывающего кода не был создан через модуль [`threading`](https://python-all.ru/3.3/library/threading.html#module-threading), возвращается фиктивный объект потока с ограниченной функциональностью.3031#### `threading.get_ident()`3233Возвращает «идентификатор потока» текущего потока. Это ненулевое целое число. Его значение не имеет прямого смысла; оно предназначено как уникальная метка, используемая, например, для индексации словаря с данными, специфичными для потока. Идентификаторы потоков могут быть переиспользованы, когда один поток завершается, а другой создаётся.3435Новое в версии 3.3.3637#### `threading.enumerate()`3839Возвращает список всех объектов [`Thread`](https://python-all.ru/3.3/library/threading.html#threading.Thread), которые в данный момент активны. Список включает потоки-демоны, фиктивные объекты потоков, созданные [`current_thread()`](https://python-all.ru/3.3/library/threading.html#threading.current_thread), и главный поток. Он исключает завершённые потоки и потоки, которые ещё не были запущены.4041#### `threading.settrace(func)`4243Устанавливает функцию трассировки для всех потоков, запущенных из модуля [`threading`](https://python-all.ru/3.3/library/threading.html#module-threading). Функция *func* будет передана в [`sys.settrace()`](https://python-all.ru/3.3/library/sys.html#sys.settrace) для каждого потока перед вызовом его метода [`run()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.run).4445#### `threading.setprofile(func)`4647Устанавливает функцию профилирования для всех потоков, запущенных из модуля [`threading`](https://python-all.ru/3.3/library/threading.html#module-threading). Функция *func* будет передана в [`sys.setprofile()`](https://python-all.ru/3.3/library/sys.html#sys.setprofile) для каждого потока перед вызовом его метода [`run()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.run).4849#### `threading.stack_size([size])`5051Возвращает размер стека потока, используемый при создании новых потоков. Необязательный аргумент *size* задаёт размер стека, который будет использоваться для впоследствии создаваемых потоков, и должен быть равен 0 (использовать платформенное или настроенное по умолчанию значение) или положительному целому числу не менее 32 768 (32 КиБ). Если изменение размера стека потока не поддерживается, возбуждается [`RuntimeError`](https://python-all.ru/3.3/library/exceptions.html#RuntimeError). Если указанный размер стека некорректен, возбуждается [`ValueError`](https://python-all.ru/3.3/library/exceptions.html#ValueError), и размер стека не изменяется. В настоящее время 32 КиБ – это минимальный поддерживаемый размер стека, гарантирующий достаточное пространство стека для самого интерпретатора. Обратите внимание, что на некоторых платформах могут действовать особые ограничения на значения размера стека, например, требование минимального размера стека \> 32 КиБ или требование выделения памяти, кратного размеру страницы системной памяти; для получения дополнительной информации следует обращаться к документации платформы (страницы по 4 КиБ распространены; при отсутствии более конкретной информации рекомендуется использовать значения размера стека, кратные 4096). Доступность: Windows, системы с POSIX-потоками.5253Этот модуль также определяет следующую константу:5455#### `threading.TIMEOUT_MAX`5657Максимально допустимое значение для параметра *timeout* блокирующих функций ([`Lock.acquire()`](https://python-all.ru/3.3/library/threading.html#threading.Lock.acquire), [`RLock.acquire()`](https://python-all.ru/3.3/library/threading.html#threading.RLock.acquire), [`Condition.wait()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.wait) и т.д.). Указание тайм-аута, превышающего это значение, вызовет исключение [`OverflowError`](https://python-all.ru/3.3/library/exceptions.html#OverflowError).5859Новое в версии 3.2.6061Этот модуль определяет ряд классов, которые подробно описаны в разделах ниже.6263Дизайн этого модуля основан на модели потоков Java, хотя и не строго. Однако, если в Java блокировки и переменные условий являются базовым поведением каждого объекта, в Python они являются отдельными объектами. Класс [`Thread`](https://python-all.ru/3.3/library/threading.html#threading.Thread) в Python поддерживает подмножество поведения класса Thread в Java; в настоящее время нет приоритетов, групп потоков, и потоки не могут быть уничтожены, остановлены, приостановлены, возобновлены или прерваны. Статические методы класса Thread в Java при их реализации отображаются на функции уровня модуля.6465Все описанные ниже методы выполняются атомарно.6667## 17.1.1. Локальные данные потока6869Потоково-локальные данные – это данные, значения которых специфичны для потока. Чтобы управлять потоково-локальными данными, достаточно создать экземпляр [`local`](https://python-all.ru/3.3/library/threading.html#threading.local) (или его подкласс) и сохранять атрибуты в нём:7071```python72mydata = threading.local()73mydata.x = 174```7576Значения экземпляра будут разными для разных потоков.7778#### `class threading.local`7980Класс, представляющий данные, локальные для потока.8182Для получения более подробной информации и многочисленных примеров обратитесь к строке документации модуля `_threading_local`.8384## 17.1.2. Объекты потоков8586Класс [`Thread`](https://python-all.ru/3.3/library/threading.html#threading.Thread) представляет действие, которое выполняется в отдельном потоке управления. Действие можно задать двумя способами: передав вызываемый объект конструктору или переопределив метод [`run()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.run) в подклассе. Никакие другие методы (кроме конструктора) не должны переопределяться в подклассе. Другими словами, *переопределяйте* только методы `__init__()` и [`run()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.run) этого класса.8788После создания объекта потока его действие необходимо запустить вызовом метода [`start()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.start) этого потока. Это вызовет метод [`run()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.run) в отдельном потоке управления.8990Когда действие потока запущено, поток считается «живым». Он перестаёт быть живым, когда его метод [`run()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.run) завершается – либо нормально, либо из-за необработанного исключения. Метод [`is_alive()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.is_alive) проверяет, жив ли поток.9192Другие потоки могут вызывать метод [`join()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.join) потока. Это блокирует вызывающий поток до тех пор, пока поток, чей метод [`join()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.join) был вызван, не завершится.9394У потока есть имя. Имя можно передать конструктору, а также прочитать или изменить через атрибут [`name`](https://python-all.ru/3.3/library/threading.html#threading.Thread.name).9596Поток может быть помечен как «поток-демон». Значение этого флага заключается в том, что вся программа Python завершается, когда остаются только потоки-демоны. Начальное значение наследуется от создающего потока. Флаг можно установить через свойство [`daemon`](https://python-all.ru/3.3/library/threading.html#threading.Thread.daemon) или аргумент конструктора *daemon*.9798> **Примечание**99>100> Потоки-демоны при завершении работы останавливаются принудительно. Их ресурсы (такие как открытые файлы, транзакции базы данных и т.п.) могут быть освобождены некорректно. Если нужно, чтобы потоки завершались корректно, сделайте их недемоническими и используйте подходящий механизм сигнализации, например [`Event`](https://python-all.ru/3.3/library/threading.html#threading.Event).101102Существует объект «главный поток»; он соответствует начальному потоку управления в программе Python. Это не фоновый поток.103104Существует возможность создания «фиктивных объектов потоков». Это объекты потоков, соответствующие «внешним потокам», то есть потокам управления, запущенным вне модуля threading, например, напрямую из C-кода. Фиктивные объекты потоков имеют ограниченную функциональность; они всегда считаются живыми и демоническими, и к ним нельзя применить [`join()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.join). Они никогда не удаляются, так как невозможно обнаружить завершение внешнего потока.105106#### `class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)`107108Этот конструктор всегда следует вызывать с именованными аргументами. Аргументы:109110Параметр *group* должен быть `None`; зарезервирован для будущего расширения, когда будет реализован класс `ThreadGroup`.111112Параметр *target* – это вызываемый объект, который будет вызван методом [`run()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.run). По умолчанию `None`, то есть ничего не вызывается.113114*name* – это имя потока. По умолчанию создаётся уникальное имя вида «Поток-*N*», где *N* – небольшое десятичное число.115116*args* – кортеж аргументов для вызова целевой функции. По умолчанию равен `()`.117118*kwargs* – это словарь именованных аргументов для вызова target. По умолчанию `{}`.119120Если не `None`, параметр *daemon* явно задаёт, является ли поток демоническим. Если `None` (по умолчанию), свойство демоничности наследуется от текущего потока.121122Если подкласс переопределяет конструктор, он должен вызывать конструктор базового класса (`Thread.__init__()`) перед любыми другими действиями с потоком.123124Изменено в версии 3.3: Добавлен аргумент *daemon*.125126#### `start()`127128Запускает выполнение потока.129130Этот метод должен вызываться не более одного раза для каждого объекта потока. Он организует вызов метода [`run()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.run) объекта в отдельном потоке управления.131132Этот метод вызовет исключение [`RuntimeError`](https://python-all.ru/3.3/library/exceptions.html#RuntimeError), если его вызвать более одного раза для одного и того же объекта потока.133134#### `run()`135136Метод, представляющий действие потока.137138Вы можете переопределить этот метод в подклассе. Стандартный метод [`run()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.run) вызывает вызываемый объект, переданный конструктору объекта как аргумент *target* (если он есть), с позиционными и именованными аргументами, взятыми из аргументов *args* и *kwargs* соответственно.139140#### `join(timeout=None)`141142Ожидает завершения потока. Этот метод блокирует вызывающий поток до тех пор, пока поток, для которого вызван метод [`join()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.join), не завершится – либо нормально, либо из-за необработанного исключения – или пока не истечёт указанное время ожидания.143144Когда аргумент *timeout* присутствует и не равен `None`, он должен быть числом с плавающей точкой, задающим время ожидания операции в секундах (или долях секунды). Поскольку [`join()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.join) всегда возвращает `None`, необходимо вызвать [`is_alive()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.is_alive) после [`join()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.join), чтобы определить, произошло ли истечение времени – если поток всё ещё жив, вызов [`join()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.join) завершился по тайм-ауту.145146Если аргумент *timeout* отсутствует или равен `None`, операция будет блокироваться до завершения потока.147148К одному потоку можно применить [`join()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.join) много раз.149150Вызов [`join()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.join) вызывает исключение [`RuntimeError`](https://python-all.ru/3.3/library/exceptions.html#RuntimeError), если предпринимается попытка присоединения к текущему потоку, поскольку это привело бы к взаимоблокировке. Также является ошибкой вызов [`join()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.join) для потока до его запуска, и такие попытки вызывают то же исключение.151152#### `name`153154Строка, используемая только для идентификации. Она не имеет семантического значения. Разным потокам можно задать одно и то же имя. Начальное имя устанавливается конструктором.155156#### `getName()`157158#### `setName()`159160Устаревший API геттера/сеттера для [`name`](https://python-all.ru/3.3/library/threading.html#threading.Thread.name); вместо этого используйте его напрямую как свойство.161162#### `ident`163164«Идентификатор потока» данного потока или `None`, если поток не был запущен. Это ненулевое целое число. Смотрите функцию [`_thread.get_ident()`](https://python-all.ru/3.3/library/_thread.html#_thread.get_ident). Идентификаторы потоков могут быть переиспользованы, когда поток завершается и создаётся новый поток. Идентификатор доступен даже после завершения потока.165166#### `is_alive()`167168Возвращает, жив ли поток.169170Этот метод возвращает `True` начиная непосредственно перед запуском метода [`run()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.run) и до момента сразу после завершения метода [`run()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.run). Функция модуля [`enumerate()`](https://python-all.ru/3.3/library/threading.html#threading.enumerate) возвращает список всех живых потоков.171172#### `daemon`173174Логическое значение, указывающее, является ли данный поток демоническим (True) или нет (False). Это значение должно быть установлено до вызова [`start()`](https://python-all.ru/3.3/library/threading.html#threading.Thread.start), иначе будет вызвано исключение [`RuntimeError`](https://python-all.ru/3.3/library/exceptions.html#RuntimeError). Его начальное значение наследуется от создающего потока; главный поток не является демоническим, и поэтому все потоки, созданные в главном потоке, по умолчанию имеют [`daemon`](https://python-all.ru/3.3/library/threading.html#threading.Thread.daemon) = `False`.175176Вся программа Python завершается, когда не остаётся ни одного живого потока, не являющегося демоном.177178#### `isDaemon()`179180#### `setDaemon()`181182Устаревший API геттера/сеттера для [`daemon`](https://python-all.ru/3.3/library/threading.html#threading.Thread.daemon); вместо этого используйте его напрямую как свойство.183184**Деталь реализации CPython:** В CPython из-за [*глобальная блокировка интерпретатора (Global Interpreter Lock)*](https://python-all.ru/3.3/glossary.html#term-global-interpreter-lock) одновременно может выполняться только один поток Python (хотя некоторые библиотеки, ориентированные на производительность, могут обойти это ограничение). Если вы хотите, чтобы ваше приложение лучше использовало вычислительные ресурсы многоядерных машин, рекомендуется использовать [`multiprocessing`](https://python-all.ru/3.3/library/multiprocessing.html#module-multiprocessing) или [`concurrent.futures.ProcessPoolExecutor`](https://python-all.ru/3.3/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor). Однако threading по-прежнему является подходящей моделью, если требуется одновременное выполнение нескольких задач, связанных с вводом-выводом.185186## 17.1.3. Объекты блокировок187188Примитивная блокировка – это синхронизационный примитив, который не принадлежит конкретному потоку в заблокированном состоянии. В Python это в настоящее время самый низкоуровневый доступный примитив синхронизации, реализованный непосредственно модулем расширения [`_thread`](https://python-all.ru/3.3/library/_thread.html#module-_thread).189190Примитивная блокировка находится в одном из двух состояний: «заблокировано» (locked) или «разблокировано» (unlocked). Она создаётся в разблокированном состоянии. Имеет два основных метода: [`acquire()`](https://python-all.ru/3.3/library/threading.html#threading.Lock.acquire) и [`release()`](https://python-all.ru/3.3/library/threading.html#threading.Lock.release). Когда состояние разблокировано, [`acquire()`](https://python-all.ru/3.3/library/threading.html#threading.Lock.acquire) переводит его в заблокированное и сразу возвращает управление. Когда состояние заблокировано, [`acquire()`](https://python-all.ru/3.3/library/threading.html#threading.Lock.acquire) блокируется до тех пор, пока вызов [`release()`](https://python-all.ru/3.3/library/threading.html#threading.Lock.release) из другого потока не переведёт его в разблокированное; после этого вызов [`acquire()`](https://python-all.ru/3.3/library/threading.html#threading.Lock.acquire) снова устанавливает заблокированное состояние и возвращает управление. Метод [`release()`](https://python-all.ru/3.3/library/threading.html#threading.Lock.release) следует вызывать только в заблокированном состоянии; он переводит состояние в разблокированное и немедленно возвращает управление. При попытке освободить разблокированную блокировку будет возбуждено исключение [`RuntimeError`](https://python-all.ru/3.3/library/exceptions.html#RuntimeError).191192Блокировки также поддерживают [*протокол контекстного менеджера*](https://python-all.ru/3.3/library/threading.html#with-locks).193194Когда несколько потоков заблокированы в вызове [`acquire()`](https://python-all.ru/3.3/library/threading.html#threading.Lock.acquire) в ожидании разблокировки состояния, только один поток продолжает работу после того, как вызов [`release()`](https://python-all.ru/3.3/library/threading.html#threading.Lock.release) переведёт состояние в разблокированное; какой именно из ожидающих потоков продолжит работу – не определено и может различаться в разных реализациях.195196Все методы выполняются атомарно.197198#### `class threading.Lock`199200Класс, реализующий объекты примитивной блокировки. Как только поток захватил блокировку, последующие попытки захватить её блокируются до тех пор, пока она не будет освобождена; любой поток может освободить её.201202Изменено в версии 3.3: Изменён с фабричной функции на класс.203204#### `acquire(blocking=True, timeout=-1)`205206Захватывает блокировку, блокирующую или неблокирующую.207208При вызове с аргументом *blocking*, установленным в `True` (по умолчанию), блокирует выполнение до тех пор, пока блокировка не будет разблокирована, после чего устанавливает её в заблокированное состояние и возвращает `True`.209210При вызове с аргументом *blocking*, установленным в `False`, блокировка не выполняется. Если вызов с *blocking*, установленным в `True`, привёл бы к блокировке, немедленно возвращается `False`; в противном случае блокировка устанавливается в заблокированное состояние и возвращается `True`.211212Если при вызове аргументу *timeout* с плавающей запятой задано положительное значение, блокировка происходит на время не более указанного *timeout* секунд, пока не будет получена блокировка. Значение *timeout*, равное `-1`, означает бесконечное ожидание. Запрещено указывать *timeout*, когда *blocking* равно false.213214Возвращаемое значение – `True`, если блокировка успешно захвачена, или `False` в противном случае (например, если истёк *тайм-аут*).215216Изменено в версии 3.2: Параметр *timeout* является новым.217218Изменено в версии 3.2: Захват блокировки теперь может прерываться сигналами на POSIX.219220#### `release()`221222Освобождает блокировку. Может вызываться из любого потока, а не только из того, который захватил блокировку.223224Когда блокировка установлена, сбрасывает её в снятое состояние и возвращает управление. Если другие потоки заблокированы в ожидании освобождения блокировки, ровно одному из них разрешается продолжить работу.225226При вызове на незахваченной блокировке возбуждается [`RuntimeError`](https://python-all.ru/3.3/library/exceptions.html#RuntimeError).227228Возвращаемое значение отсутствует.229230## 17.1.4. Объекты RLock231232Повторно входимая блокировка – это примитив синхронизации, который может быть захвачен одним и тем же потоком несколько раз. Внутри она использует понятия «поток-владелец» и «уровень рекурсии» в дополнение к состоянию «заблокировано/разблокировано», используемому простыми блокировками. В заблокированном состоянии блокировкой владеет какой-то поток; в разблокированном состоянии ею не владеет ни один поток.233234Для блокировки поток вызывает свой метод [`acquire()`](https://python-all.ru/3.3/library/threading.html#threading.RLock.acquire); этот метод возвращает управление, когда поток получает во владение блокировку. Для разблокировки поток вызывает свой метод [`release()`](https://python-all.ru/3.3/library/threading.html#threading.Lock.release). Пары вызовов [`acquire()`](https://python-all.ru/3.3/library/threading.html#threading.Lock.acquire)/[`release()`](https://python-all.ru/3.3/library/threading.html#threading.Lock.release) могут быть вложенными; только последний вызов [`release()`](https://python-all.ru/3.3/library/threading.html#threading.Lock.release) (самый внешний [`release()`](https://python-all.ru/3.3/library/threading.html#threading.Lock.release)) переводит блокировку в разблокированное состояние и позволяет другому потоку, заблокированному в [`acquire()`](https://python-all.ru/3.3/library/threading.html#threading.Lock.acquire), продолжить работу.235236Рекурсивные блокировки также поддерживают [*протокол контекстного менеджера*](https://python-all.ru/3.3/library/threading.html#with-locks).237238#### `class threading.RLock`239240Этот класс реализует объекты повторно входимой блокировки. Повторно входимая блокировка должна быть освобождена тем же потоком, который её захватил. После того как поток захватил повторно входимую блокировку, этот же поток может захватить её снова без блокировки; при этом поток должен освободить её один раз за каждый захват.241242Обратите внимание, что `RLock` на самом деле является фабричной функцией, которая возвращает экземпляр наиболее эффективной версии конкретного класса RLock, поддерживаемой платформой.243244#### `acquire(blocking=True, timeout=-1)`245246Захватывает блокировку, блокирующую или неблокирующую.247248При вызове без аргументов: если этот поток уже владеет блокировкой, увеличить уровень рекурсии на единицу и немедленно вернуться. В противном случае, если блокировкой владеет другой поток, блокироваться до тех пор, пока блокировка не будет освобождена. Как только блокировка освобождена (не принадлежит ни одному потоку), захватить владение, установить уровень рекурсии в единицу и вернуться. Если несколько потоков заблокированы в ожидании освобождения блокировки, только один из них сможет захватить владение. В этом случае возвращаемого значения нет.249250При вызове с аргументом *blocking*, установленным в true, делает то же самое, что и при вызове без аргументов, и возвращает true.251252При вызове с аргументом *blocking*, установленным в false, не блокируется. Если вызов без аргументов привёл бы к блокировке, немедленно возвращает false; в противном случае делает то же самое, что и при вызове без аргументов, и возвращает true.253254При вызове с аргументом *timeout* типа float, установленным в положительное значение, блокируется не более чем на число секунд, указанное в *timeout*, и до тех пор, пока блокировка не будет получена. Возвращает True, если блокировка получена, и False, если истекло время ожидания.255256Изменено в версии 3.2: Параметр *timeout* является новым.257258#### `release()`259260Освобождает блокировку, уменьшая уровень рекурсии. Если после уменьшения он становится нулевым, сбрасывает блокировку в разблокированное состояние (не принадлежит ни одному потоку), и, если другие потоки заблокированы в ожидании освобождения блокировки, ровно одному из них разрешается продолжить. Если после уменьшения уровень рекурсии всё ещё ненулевой, блокировка остаётся заблокированной и принадлежит вызывающему потоку.261262Вызывайте этот метод только тогда, когда вызывающий поток владеет блокировкой. Исключение [`RuntimeError`](https://python-all.ru/3.3/library/exceptions.html#RuntimeError) возбуждается, если этот метод вызван, когда блокировка разблокирована.263264Возвращаемое значение отсутствует.265266## 17.1.5. Объекты условий267268Переменная условия всегда связана с какой-либо блокировкой; её можно передать, или же она будет создана по умолчанию. Передача блокировки полезна, когда несколько переменных условия должны совместно использовать одну и ту же блокировку. Блокировка является частью объекта условия: не нужно отслеживать её отдельно.269270Переменная условия подчиняется [*протоколу контекстного менеджера*](https://python-all.ru/3.3/library/threading.html#with-locks): использование оператора `with` захватывает связанную блокировку на время вложенного блока. Методы [`acquire()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.acquire) и [`release()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.release) также вызывают соответствующие методы связанной блокировки.271272Другие методы должны вызываться только при удержании связанной блокировки. Метод [`wait()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.wait) освобождает блокировку и затем блокируется, пока другой поток не пробудит его вызовом [`notify()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify) или [`notify_all()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify_all). После пробуждения [`wait()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.wait) повторно захватывает блокировку и возвращает управление. Также можно указать тайм-аут.273274Метод [`notify()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify) пробуждает один из потоков, ожидающих на данной условной переменной (если такие есть). Метод [`notify_all()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify_all) пробуждает все потоки, ожидающие на условной переменной.275276Примечание: методы [`notify()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify) и [`notify_all()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify_all) не освобождают блокировку; это означает, что пробуждённый поток (или потоки) не вернутся из своего вызова [`wait()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.wait) немедленно, а только тогда, когда поток, вызвавший [`notify()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify) или [`notify_all()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify_all), окончательно откажется от владения блокировкой.277278Типичный стиль программирования с использованием условных переменных заключается в том, чтобы использовать блокировку для синхронизации доступа к некоторому общему состоянию; потоки, заинтересованные в определённом изменении состояния, вызывают [`wait()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.wait) многократно, пока не увидят желаемое состояние, тогда как потоки, изменяющие состояние, вызывают [`notify()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify) или [`notify_all()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify_all), когда они изменяют состояние таким образом, что оно может оказаться желаемым для одного из ожидающих потоков. Например, следующий код представляет собой обобщённую ситуацию «производитель-потребитель» с неограниченной ёмкостью буфера:279280```python281# Потребить один элемент282with cv:283    while not an_item_is_available():284        cv.wait()285    get_an_available_item()286287# Произвести один элемент288with cv:289    make_an_item_available()290    cv.notify()291```292293Цикл `while`, проверяющий условие приложения, необходим, потому что [`wait()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.wait) может вернуть управление спустя произвольно долгое время, и условие, которое привело к вызову [`notify()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify), может уже не выполняться. Это присуще многопоточному программированию. Метод [`wait_for()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.wait_for) можно использовать для автоматизации проверки условия, что упрощает вычисление тайм-аутов:294295```python296# Потребить элемент297with cv:298    cv.wait_for(an_item_is_available)299    get_an_available_item()300```301302При выборе между [`notify()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify) и [`notify_all()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify_all) учитывайте, может ли одно изменение состояния быть интересно только одному или нескольким ожидающим потокам. Например, в типичной ситуации «производитель-потребитель» добавление одного элемента в буфер требует пробуждения только одного потока-потребителя.303304#### `class threading.Condition(lock=None)`305306Этот класс реализует объекты переменной условия. Переменная условия позволяет одному или нескольким потокам ожидать, пока другой поток не уведомит их.307308Если аргумент *блокировка* задан и не равен `None`, то он должен быть объектом [`блокировка`](https://python-all.ru/3.3/library/threading.html#threading.Lock) или [`RLock`](https://python-all.ru/3.3/library/threading.html#threading.RLock) и использоваться в качестве базовой блокировки. В противном случае создаётся новый объект [`RLock`](https://python-all.ru/3.3/library/threading.html#threading.RLock), который используется как базовая блокировка.309310Изменено в версии 3.3: изменён с фабричной функции на класс.311312#### `acquire(*args)`313314Захватывает базовую блокировку. Этот метод вызывает соответствующий метод базовой блокировки; возвращаемое значение – то, что возвращает этот метод.315316#### `release()`317318Освобождает базовую блокировку. Этот метод вызывает соответствующий метод базовой блокировки; возвращаемое значение отсутствует.319320#### `wait(timeout=None)`321322Ожидает до получения уведомления или до истечения тайм-аута. Если вызывающий поток не захватил блокировку на момент вызова этого метода, возбуждается исключение [`RuntimeError`](https://python-all.ru/3.3/library/exceptions.html#RuntimeError).323324Этот метод освобождает базовую блокировку, а затем блокируется до тех пор, пока не будет пробуждён вызовом [`notify()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify) или [`notify_all()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify_all) для той же условной переменной из другого потока, или пока не наступит опциональный тайм-аут. После пробуждения или истечения тайм-аута он повторно захватывает блокировку и возвращает управление.325326Если аргумент *timeout* присутствует и не равен `None`, то он должен быть числом с плавающей запятой, указывающим тайм-аут для операции в секундах (или долях секунды).327328Если базовая блокировка является объектом [`RLock`](https://python-all.ru/3.3/library/threading.html#threading.RLock), то она не освобождается с помощью его метода [`release()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.release), поскольку этот метод может фактически не разблокировать блокировку, если она была захвачена несколько раз рекурсивно. Вместо этого используется внутренний интерфейс класса [`RLock`](https://python-all.ru/3.3/library/threading.html#threading.RLock), который действительно разблокирует её, даже если она была рекурсивно захвачена несколько раз. Затем другой внутренний интерфейс восстанавливает уровень рекурсии при повторном захвате блокировки.329330Возвращаемое значение равно `True`, если только не истёк заданный *тайм-аут*; в этом случае возвращается `False`.331332Изменено в версии 3.2: Ранее метод всегда возвращал `None`.333334#### `wait_for(predicate, timeout=None)`335336Ожидание, пока условие не станет истинным (True). *predicate* должен быть вызываемым объектом, результат которого будет интерпретироваться как логическое значение. Можно указать *timeout*, задающий максимальное время ожидания.337338Этот вспомогательный метод может многократно вызывать [`wait()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.wait), пока предикат не будет выполнен или пока не истечет время ожидания. Возвращаемое значение – это последнее возвращаемое значение предиката, и оно будет равно `False`, если метод завершился по тайм-ауту.339340Если не учитывать возможность тайм-аута, вызов этого метода примерно эквивалентен следующему коду:341342```python343while not predicate():344    cv.wait()345```346347Поэтому применяются те же правила, что и для [`wait()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.wait): блокировка должна быть захвачена при вызове и повторно захватывается при возврате. Предикат вычисляется при захваченной блокировке.348349Новое в версии 3.2.350351#### `notify(n=1)`352353По умолчанию пробуждает один поток, ожидающий на этом условии, если таковой имеется. Если вызывающий поток не захватил блокировку при вызове этого метода, возникает исключение [`RuntimeError`](https://python-all.ru/3.3/library/exceptions.html#RuntimeError).354355Этот метод пробуждает не более *n* потоков, ожидающих на переменной условия; если ни один поток не ожидает, он ничего не делает.356357Текущая реализация пробуждает ровно *n* потоков, если ожидает не менее *n* потоков. Однако полагаться на такое поведение небезопасно. В будущем оптимизированная реализация может иногда пробуждать более *n* потоков.358359Примечание: пробужденный поток фактически не возвращается из своего вызова [`wait()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.wait), пока не сможет повторно захватить блокировку. Поскольку [`notify()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify) не освобождает блокировку, это должен сделать вызвавший её поток.360361#### `notify_all()`362363Пробуждает все потоки, ожидающие на этом условии. Этот метод действует как [`notify()`](https://python-all.ru/3.3/library/threading.html#threading.Condition.notify), но пробуждает все ожидающие потоки вместо одного. Если вызывающий поток не захватил блокировку при вызове этого метода, возникает исключение [`RuntimeError`](https://python-all.ru/3.3/library/exceptions.html#RuntimeError).364365## 17.1.6. Объекты семафоров366367Это один из старейших примитивов синхронизации в истории информатики, изобретенный ранним нидерландским учёным Эдсгером В. Дейкстрой (он использовал имена `P()` и `V()` вместо [`acquire()`](https://python-all.ru/3.3/library/threading.html#threading.Semaphore.acquire) и [`release()`](https://python-all.ru/3.3/library/threading.html#threading.Semaphore.release)).368369Семафор управляет внутренним счётчиком, который уменьшается при каждом вызове [`acquire()`](https://python-all.ru/3.3/library/threading.html#threading.Semaphore.acquire) и увеличивается при каждом вызове [`release()`](https://python-all.ru/3.3/library/threading.html#threading.Semaphore.release). Счётчик никогда не может стать меньше нуля; когда [`acquire()`](https://python-all.ru/3.3/library/threading.html#threading.Semaphore.acquire) обнаруживает, что он равен нулю, он блокируется, ожидая, пока другой поток вызовет [`release()`](https://python-all.ru/3.3/library/threading.html#threading.Semaphore.release).370371Семафоры также поддерживают [*протокол менеджера контекста*](https://python-all.ru/3.3/library/threading.html#with-locks).372373#### `class threading.Semaphore(value=1)`374375Этот класс реализует объекты-семафоры. Семафор управляет счётчиком, представляющим количество вызовов [`release()`](https://python-all.ru/3.3/library/threading.html#threading.Semaphore.release) минус количество вызовов [`acquire()`](https://python-all.ru/3.3/library/threading.html#threading.Semaphore.acquire), плюс начальное значение. Метод [`acquire()`](https://python-all.ru/3.3/library/threading.html#threading.Semaphore.acquire) блокируется при необходимости, пока не сможет вернуться, не сделав счётчик отрицательным. Если не указано, *value* по умолчанию равен 1.376377Необязательный аргумент задаёт начальное *value* для внутреннего счётчика; по умолчанию оно равно `1`. Если указанное *value* меньше 0, возникает исключение [`ValueError`](https://python-all.ru/3.3/library/exceptions.html#ValueError).378379Изменено в версии 3.3: изменён с фабричной функции на класс.380381#### `acquire(blocking=True, timeout=None)`382383Захватывает семафор.384385При вызове без аргументов: если внутренний счётчик при входе больше нуля, уменьшить его на единицу и сразу вернуться. Если он равен нулю, заблокироваться, ожидая, пока другой поток вызовет [`release()`](https://python-all.ru/3.3/library/threading.html#threading.Semaphore.release), чтобы сделать его больше нуля. Это делается с надлежащей взаимной блокировкой, так что если несколько вызовов [`acquire()`](https://python-all.ru/3.3/library/threading.html#threading.Semaphore.acquire) заблокированы, [`release()`](https://python-all.ru/3.3/library/threading.html#threading.Semaphore.release) пробудит ровно один из них. Реализация может выбрать любой случайным образом, поэтому на порядок пробуждения заблокированных потоков полагаться не следует. Возвращает true (или блокируется на неопределённый срок).386387При вызове с *blocking*, установленным в false, не блокироваться. Если вызов без аргумента заблокировался бы, немедленно вернуть false; в противном случае сделать то же самое, что и при вызове без аргументов, и вернуть true.388389При вызове с *timeout*, отличным от None, он будет блокироваться не более *timeout* секунд. Если acquire не завершится успешно за это время, вернуть false. В противном случае вернуть true.390391Изменено в версии 3.2: Параметр *timeout* является новым.392393#### `release()`394395Освобождает семафор, увеличивая внутренний счётчик на единицу. Когда он был равен нулю при входе и другой поток ожидает, когда он снова станет больше нуля, пробуждает этот поток.396397#### `class threading.BoundedSemaphore(value=1)`398399Класс, реализующий ограниченные семафоры (bounded semaphore). Ограниченный семафор проверяет, что его текущее значение не превышает начальное. Если превышает, возникает исключение [`ValueError`](https://python-all.ru/3.3/library/exceptions.html#ValueError). В большинстве ситуаций семафоры используются для защиты ресурсов с ограниченной ёмкостью. Если семафор освобождается слишком много раз, это признак ошибки. Если не указано, *value* по умолчанию равен 1.400401Изменено в версии 3.3: изменён с фабричной функции на класс.402403### 17.1.6.1. [`Semaphore`](https://python-all.ru/3.3/library/threading.html#threading.Semaphore) Пример404405Семафоры часто используются для защиты ресурсов с ограниченной ёмкостью, например, сервера базы данных. В любой ситуации, когда размер ресурса фиксирован, следует использовать ограниченный семафор. Перед запуском рабочих потоков главный поток инициализирует семафор:406407```python408maxconnections = 5409# ...410pool_sema = BoundedSemaphore(value=maxconnections)411```412413После запуска рабочие потоки вызывают методы acquire и release семафора, когда им нужно подключиться к серверу:414415```python416with pool_sema:417    conn = connectdb()418    try:419        # ... использовать соединение ...420    finally:421        conn.close()422```423424Использование ограниченного семафора снижает вероятность того, что ошибка программирования, приводящая к освобождению семафора большее количество раз, чем его захват, останется незамеченной.425426## 17.1.7. Объекты событий427428Это один из простейших механизмов взаимодействия между потоками: один поток сигнализирует о событии, а другие потоки ожидают его.429430Объект-событие управляет внутренним флагом, который может быть установлен в true методом [`set()`](https://python-all.ru/3.3/library/threading.html#threading.Event.set) и сброшен в false методом [`clear()`](https://python-all.ru/3.3/library/threading.html#threading.Event.clear). Метод [`wait()`](https://python-all.ru/3.3/library/threading.html#threading.Event.wait) блокируется, пока флаг не станет true.431432#### `class threading.Event`433434Класс, реализующий объекты-события. Событие управляет флагом, который может быть установлен в true методом [`set()`](https://python-all.ru/3.3/library/threading.html#threading.Event.set) и сброшен в false методом [`clear()`](https://python-all.ru/3.3/library/threading.html#threading.Event.clear). Метод [`wait()`](https://python-all.ru/3.3/library/threading.html#threading.Event.wait) блокируется, пока флаг не станет true. Изначально флаг равен false.435436Изменено в версии 3.3: изменён с фабричной функции на класс.437438#### `is_set()`439440Возвращает true тогда и только тогда, когда внутренний флаг равен true.441442#### `set()`443444Устанавливает внутренний флаг в true. Все потоки, ожидающие его установки в true, пробуждаются. Потоки, которые вызывают [`wait()`](https://python-all.ru/3.3/library/threading.html#threading.Event.wait) после того, как флаг уже true, не будут блокироваться вообще.445446#### `clear()`447448Сбрасывает внутренний флаг в false. После этого потоки, вызывающие [`wait()`](https://python-all.ru/3.3/library/threading.html#threading.Event.wait), будут блокироваться до тех пор, пока не будет вызван [`set()`](https://python-all.ru/3.3/library/threading.html#threading.Event.set), чтобы снова установить флаг в true.449450#### `wait(timeout=None)`451452Блокируется, пока внутренний флаг не станет true. Если при входе флаг уже true, вернуться немедленно. В противном случае блокироваться до тех пор, пока другой поток не вызовет [`set()`](https://python-all.ru/3.3/library/threading.html#threading.Event.set), чтобы установить флаг в true, или пока не истечет необязательный тайм-аут.453454Если аргумент timeout присутствует и не равен `None`, он должен быть числом с плавающей точкой, задающим таймаут для операции в секундах (или долях секунды).455456Этот метод возвращает True тогда и только тогда, когда внутренний флаг был установлен в True (до вызова wait или в процессе ожидания). Таким образом, он всегда возвращает `True`, за исключением случаев, когда указан таймаут и его время истекло.457458Изменено в версии 3.1: Ранее метод всегда возвращал `None`.459460## 17.1.8. Объекты таймеров461462Этот класс представляет действие, которое должно быть выполнено только после того, как пройдет определенное время – таймер. [`Timer`](https://python-all.ru/3.3/library/threading.html#threading.Timer) является подклассом [`Thread`](https://python-all.ru/3.3/library/threading.html#threading.Thread) и, таким образом, служит примером создания пользовательских потоков.463464Таймеры запускаются, как и потоки, вызовом их метода `start()`. Таймер можно остановить (до начала его действия) вызовом метода [`cancel()`](https://python-all.ru/3.3/library/threading.html#threading.Timer.cancel). Интервал, который таймер будет ждать перед выполнением своего действия, может не в точности совпадать с интервалом, указанным пользователем.465466Например:467468```python469def hello():470    print("hello, world")471472t = Timer(30.0, hello)473t.start() # через 30 секунд будет выведено "hello, world"474```475476#### `class threading.Timer(interval, function, args=None, kwargs=None)`477478Создает таймер, который запустит *function* с аргументами *args* и именованными аргументами *kwargs* по прошествии *interval* секунд. Если *args* равно None (по умолчанию), будет использован пустой список. Если *kwargs* равно None (по умолчанию), будет использован пустой словарь.479480Изменено в версии 3.3: изменён с фабричной функции на класс.481482#### `cancel()`483484Останавливает таймер и отменяет выполнение его действия. Это сработает, только если таймер всё ещё находится в стадии ожидания.485486## 17.1.9. Объекты барьеров487488Новое в версии 3.2.489490Этот класс предоставляет простой примитив синхронизации для использования фиксированным количеством потоков, которым нужно дождаться друг друга. Каждый поток пытается пройти барьер, вызывая метод [`wait()`](https://python-all.ru/3.3/library/threading.html#threading.Barrier.wait), и блокируется до тех пор, пока все потоки не сделают вызов. В этот момент потоки освобождаются одновременно.491492Барьер можно использовать повторно любое количество раз для того же числа потоков.493494В качестве примера приведён простой способ синхронизации потоков клиента и сервера:495496```python497b = Barrier(2, timeout=5)498499def server():500    start_server()501    b.wait()502    while True:503        connection = accept_connection()504        process_server_connection(connection)505506def client():507    b.wait()508    while True:509        connection = make_connection()510        process_client_connection(connection)511```512513#### `class threading.Barrier(parties, action=None, timeout=None)`514515Создает объект барьера для *parties* потоков. Параметр *action*, если указан, должен быть вызываемым объектом, который будет вызван одним из потоков при их освобождении. *timeout* – это значение таймаута по умолчанию, если оно не задано для метода [`wait()`](https://python-all.ru/3.3/library/threading.html#threading.Barrier.wait).516517#### `wait(timeout=None)`518519Пройти барьер. Когда все потоки-участники барьера вызовут эту функцию, они все освобождаются одновременно. Если указан *timeout*, он используется с приоритетом перед любым значением, переданным конструктору класса.520521Возвращаемое значение – целое число в диапазоне от 0 до *parties* – 1, различное для каждого потока. Это можно использовать для выбора потока, который выполнит специальные вспомогательные действия, например:522523```python524i = barrier.wait()525if i == 0:526    # Выводить это должен только один поток527    print("passed the barrier")528```529530Если конструктору был передан *action*, один из потоков вызовет его перед освобождением. Если этот вызов вызовет ошибку, барьер переводится в состояние сбоя.531532Если вызов истекает по таймауту, барьер переводится в сломанное состояние.533534Этот метод может возбудить исключение [`BrokenBarrierError`](https://python-all.ru/3.3/library/threading.html#threading.BrokenBarrierError), если барьер был поврежден или сброшен, пока поток ожидает.535536#### `reset()`537538Возвращает барьер в исходное пустое состояние. Все потоки, ожидающие на нем, получат исключение [`BrokenBarrierError`](https://python-all.ru/3.3/library/threading.html#threading.BrokenBarrierError).539540Обратите внимание, что использование этой функции может потребовать внешней синхронизации, если есть другие потоки, состояние которых неизвестно. Если барьер сломан, возможно, лучше просто оставить его и создать новый.541542#### `abort()`543544Переводит барьер в поврежденное состояние. Это приводит к тому, что любые текущие или будущие вызовы [`wait()`](https://python-all.ru/3.3/library/threading.html#threading.Barrier.wait) завершаются ошибкой с [`BrokenBarrierError`](https://python-all.ru/3.3/library/threading.html#threading.BrokenBarrierError). Используйте это, например, если один из потоков необходимо прервать, чтобы избежать взаимоблокировки приложения.545546Возможно, предпочтительнее просто создать барьер с разумным значением *timeout*, чтобы автоматически защититься от сбоя одного из потоков.547548#### `parties`549550Количество потоков, необходимое для прохождения барьера.551552#### `n_waiting`553554Количество потоков, ожидающих в данный момент на барьере.555556#### `broken`557558Булево значение, которое равно `True`, если барьер находится в поврежденном состоянии.559560#### `exception threading.BrokenBarrierError`561562Это исключение, являющееся подклассом [`RuntimeError`](https://python-all.ru/3.3/library/exceptions.html#RuntimeError), возбуждается, когда объект [`Barrier`](https://python-all.ru/3.3/library/threading.html#threading.Barrier) сбрасывается или повреждается.563564## 17.1.10. Использование блокировок, условий и семафоров в операторе [`with`](https://python-all.ru/3.3/reference/compound_stmts.html#with)565566Все объекты, предоставляемые этим модулем, которые имеют методы `acquire()` и `release()`, могут использоваться как контекстные менеджеры в операторе [`with`](https://python-all.ru/3.3/reference/compound_stmts.html#with). Метод `acquire()` будет вызван при входе в блок, а `release()` – при выходе из блока. Следовательно, следующий фрагмент:567568```python569with some_lock:570    # выполнить какие-то действия...571```572573эквивалентно:574575```python576some_lock.acquire()577try:578    # выполнить какие-то действия...579finally:580    some_lock.release()581```582583В настоящее время объекты [`Lock`](https://python-all.ru/3.3/library/threading.html#threading.Lock), [`RLock`](https://python-all.ru/3.3/library/threading.html#threading.RLock), [`Condition`](https://python-all.ru/3.3/library/threading.html#threading.Condition), [`Semaphore`](https://python-all.ru/3.3/library/threading.html#threading.Semaphore) и [`BoundedSemaphore`](https://python-all.ru/3.3/library/threading.html#threading.BoundedSemaphore) могут использоваться как контекстные менеджеры в операторе [`with`](https://python-all.ru/3.3/reference/compound_stmts.html#with).584