threading — Параллелизм на основе потоков
Исходный код: Lib/threading.py
Этот модуль создаёт интерфейсы потоков более высокого уровня на основе модуля более низкого уровня _thread.
Изменено в версии 3.7: Этот модуль раньше был необязательным, теперь он всегда доступен.
См. также
concurrent.futures.ThreadPoolExecutor предлагает интерфейс более высокого уровня для отправки задач в фоновый поток без блокировки выполнения вызывающего потока, при этом все еще позволяя получать их результаты по мере необходимости.
queue предоставляет потокобезопасный интерфейс для обмена данными между работающими потоками.
asyncio предлагает альтернативный подход к достижению параллелизма на уровне задач без необходимости использования нескольких потоков операционной системы.
Примечание
В серии Python 2.x этот модуль содержал camelCase имена для некоторых методов и функций. Они устарели начиная с Python 3.10, но все еще поддерживаются для совместимости с Python 2.5 и ниже.
Деталь реализации CPython: В CPython, из-за глобальной блокировки интерпретатора, только один поток может выполнять код Python одновременно (хотя некоторые библиотеки, ориентированные на производительность, могут обойти это ограничение). Если вы хотите, чтобы ваше приложение лучше использовало вычислительные ресурсы многоядерных машин, рекомендуется использовать multiprocessing или concurrent.futures.ProcessPoolExecutor. Однако потоки все еще являются подходящей моделью, если вы хотите запустить несколько задач, связанных с вводом-выводом, одновременно.
Доступность: не Emscripten, не WASI.
Этот модуль не работает или недоступен на платформах WebAssembly wasm32-emscripten и wasm32-wasi. Дополнительную информацию см. в разделе Платформы WebAssembly.
Этот модуль определяет следующие функции:
-
threading.active_count() -
Возвращает количество
Threadобъектов, которые в настоящее время активны. Возвращаемое значение равно длине списка, возвращаемого функциейenumerate().Функция
activeCount— устаревшее алиас для этой функции.
-
threading.current_thread() -
Возвращает текущий объект
Thread, соответствующий потоку управления вызывающей стороны. Если поток управления вызывающей стороны не был создан с помощью модуляthreading, возвращается объект-заглушка потока с ограниченными возможностями.Функция
currentThread— устаревшее алиас для этой функции.
-
threading.excepthook(args, /) -
Обрабатывает необработанное исключение, вызванное
Thread.run().Аргумент args имеет следующие атрибуты:
- exc_type: Тип исключения.
-
exc_value: Значение исключения, может быть
None. -
exc_traceback: Трассировка стека исключения, может быть
None. -
thread: Поток, который вызвал исключение, может быть
None.
Если exc_type равен
SystemExit, исключение игнорируется. В противном случае исключение печатается вsys.stderr.Если эта функция вызывает исключение, вызывается
sys.excepthook()для его обработки.threading.excepthook()может быть переопределён для управления тем, как обрабатываются необработанные исключения, вызываемыеThread.run().Сохранение exc_value с помощью пользовательской функции может создать цикл ссылок. Он должен быть явно очищен для разрыва цикла ссылок, когда исключение больше не требуется.
Сохранение thread с помощью пользовательской функции может воскресить его, если оно присвоено объекту, который завершается. Избегайте сохранения thread после завершения пользовательской функции, чтобы предотвратить воскрешение объектов.
См. также
sys.excepthook()обрабатывает необработанные исключения.Добавлена в версии 3.8.
-
threading.__excepthook__ -
Содержит исходное значение
threading.excepthook(). Оно сохраняется, чтобы исходное значение можно было восстановить в случае, если они заменены сломанными или альтернативными объектами.Добавлена в версии 3.10.
-
threading.get_ident() -
Возвращает идентификатор потока текущего потока. Это целое число, отличное от нуля. Его значение не имеет прямого смысла; оно предназначено, например, в качестве магического значения для индексации словаря данных, специфичных для потока. Идентификаторы потоков могут быть повторно использованы при завершении потока и создании другого.
Добавлена в версии 3.3.
-
threading.get_native_id() -
Возвращает целое число идентификатора потока ядра текущего потока, назначенное ядром. Это целое неотрицательное число. Его значение может быть использовано для уникальной идентификации этого конкретного потока во всей системе (пока поток не завершит работу, после чего значение может быть повторно использовано ОС).
Доступность: Windows, FreeBSD, Linux, macOS, OpenBSD, NetBSD, AIX.
Добавлена в версии 3.8.
-
threading.enumerate() -
Возвращает список всех
Threadобъектов, которые в настоящее время активны. Список включает демонические потоки и объекты-заглушки потоков, созданныеcurrent_thread(). Он исключает завершенные потоки и потоки, которые еще не были начаты. Однако основной поток всегда входит в результат, даже при завершении.
-
threading.main_thread() -
Возвращает основной
Threadобъект. В обычных условиях основной поток — это поток, из которого был запущен интерпретатор Python.Добавлена в версии 3.4.
-
threading.settrace(func) -
Устанавливает функцию отслеживания для всех потоков, запущенных из модуля
threading. Функция func будет передана вsys.settrace()для каждого потока перед вызовом методаrun().
-
threading.gettrace() -
Получить функцию отслеживания, установленную функцией
settrace().Добавлена в версии 3.10.
-
threading.setprofile(func) -
Устанавливает функцию профилирования для всех потоков, запущенных из модуля
threading. Функция func будет передана вsys.setprofile()для каждого потока перед вызовом методаrun().
-
threading.getprofile() -
Получить функцию профилирования, установленную функцией
setprofile().Добавлена в версии 3.10.
-
threading.stack_size([size]) -
Возвращает размер стека потока, используемого при создании новых потоков. Опциональный аргумент size задаёт размер стека для последующих создаваемых потоков и должен быть равен 0 (используется платформа или настроенное значение по умолчанию) или положительным целым числом не менее 32768 (32 КБ). Если size не указан, используется 0. Если изменение размера стека потока не поддерживается, генерируется исключение
RuntimeError. Если указанный размер стека недопустим, генерируется исключениеValueError, и размер стека не изменяется. В настоящее время минимальный поддерживаемый размер стека составляет 32 КБ для обеспечения достаточного пространства стека для самого интерпретатора. Обратите внимание, что на некоторых платформах могут быть определённые ограничения на значения размера стека, такие как требование минимального размера стека > 32 КБ или требование выделения кратно размеру страницы системной памяти — для получения дополнительной информации следует обратиться к документации платформы (4 КБ страницы являются распространённым вариантом; использование кратных значений 4096 для размера стека является рекомендуемым подходом в отсутствие более конкретной информации).Доступность: Windows, pthreads.
Платформы Unix с поддержкой POSIX потоков.
Этот модуль также определяет следующую константу:
-
threading.TIMEOUT_MAX -
Максимальное значение, разрешённое для параметра timeout блокирующих функций (
Lock.acquire(),RLock.acquire(),Condition.wait()и т. д.). Указание значения таймаута, большего этого значения, приведёт к возбуждению исключенияOverflowError.Введено в версии 3.2.
Этот модуль определяет ряд классов, подробное описание которых приведено в разделах ниже.
Архитектура этого модуля частично основана на модели потоков Java. Однако в Java блокировки и условия являются базовым поведением каждого объекта, в то время как в Python они являются отдельными объектами. Класс Python Thread поддерживает подмножество поведения класса Thread Java; в настоящее время отсутствуют приоритеты, группы потоков, и потоки нельзя уничтожить, остановить, приостановить, возобновить или прервать. Статические методы класса Java Thread, при их реализации, отображаются в функции уровня модуля.
Все методы, описанные ниже, выполняются атомарно.
Данные, локальные для потока
Данные, локальные для потока, — это данные, значения которых специфичны для каждого потока. Для управления данными, локальными для потока, необходимо создать экземпляр класса local (или подкласса) и хранить атрибуты в нём:
mydata = threading.local() mydata.x = 1
Значения экземпляра будут различными для отдельных потоков.
-
class threading.local -
Класс, представляющий данные, локальные для потока.
Для получения более подробной информации и расширенных примеров см. строку документации модуля
_threading_local: Lib/_threading_local.py.
Объекты потоков
Класс Thread представляет собой действие, выполняемое в отдельном потоке управления. Существует два способа задания действия: путём передачи вызываемого объекта конструктору или путём переопределения метода run() в подклассе. Никакие другие методы (кроме конструктора) не должны переопределяться в подклассе. Другими словами, только переопределяйте методы __init__() и run() этого класса.
После создания объекта потока его действие должно быть начато вызовом метода start() потока. Это вызывает метод run() в отдельном потоке управления.
После запуска действия потока поток считается «живым». Он перестаёт быть живым, когда его метод run() завершается — либо нормально, либо путём поднятия необработанного исключения. Метод is_alive() проверяет, жив ли поток.
Другие потоки могут вызвать метод join() потока. Это блокирует вызывающий поток до тех пор, пока поток, метод join() которого вызывается, не завершится.
Поток имеет имя. Имя можно передать конструктору и прочитать или изменить через атрибут name.
Если метод run() вызывает исключение, вызывается threading.excepthook() для его обработки. По умолчанию, threading.excepthook() игнорирует SystemExit молчаливо.
Поток можно пометить как «поток-демон». Значение этого флага заключается в том, что вся программа Python завершается, когда остаются только потоки-демоны. Начальное значение наследуется от создающего потока. Флаг можно установить через свойство daemon или аргумент конструктора daemon.
Примечание
Потоки-демоны резко останавливаются при завершении работы. Их ресурсы (например, открытые файлы, транзакции баз данных и т. д.) могут быть некорректно освобождены. Если вы хотите, чтобы ваши потоки завершались корректно, сделайте их не-демонами и используйте подходящий механизм сигнализации, такой как Event.
Существует объект «главный поток»; он соответствует начальному потоку управления в программе Python. Он не является потоком-демоном.
Возможна ситуация создания «фиктивных объектов потоков». Это объекты потоков, соответствующие «чужеродным потокам», которые являются потоками управления, запущенными вне модуля threading, например, непосредственно из кода C. Фиктивные объекты потоков обладают ограниченными функциями; они всегда считаются живыми и демоническими и не могут быть объединены. Они никогда не удаляются, так как невозможно определить завершение чужеродных потоков.
-
class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None) -
Этот конструктор всегда следует вызывать с ключевыми аргументами. Аргументы:
group должен быть
None; зарезервирован для будущего расширения, когда будет реализован классThreadGroup.target — вызываемый объект, который будет вызван методом
run(). По умолчаниюNone, то есть ничего не вызывается.name — имя потока. По умолчанию генерируется уникальное имя вида «Thread-N», где N — небольшое десятичное число, или «Thread-N (target)», где «target» —
target.__name__если указан аргумент target.args — список или кортеж аргументов для вызова целевого объекта. По умолчанию
().kwargs — словарь ключевых аргументов для вызова целевого объекта. По умолчанию
{}.Если не
None, то daemon явно устанавливает, является ли поток демоническим. ЕслиNone(по умолчанию), свойство daemon наследуется от текущего потока.Если подкласс переопределяет конструктор, он должен убедиться, что вызывается конструктор базового класса (
Thread.__init__()) прежде чем делать что-либо еще с потоком.Изменено в версии 3.10: Используйте имя target, если аргумент name опущен.
Изменено в версии 3.3: Добавлен аргумент daemon.
-
start() -
Запустить активность потока.
Должен быть вызван не более одного раза на объект потока. Он организует вызов метода объекта
run()в отдельном потоке управления.Этот метод вызовет
RuntimeError, если будет вызван более одного раза для одного и того же объекта потока.
-
run() -
Метод, представляющий активность потока.
Вы можете переопределить этот метод в подклассе. Стандартный метод
run()вызывает вызываемый объект, переданный в конструктор объекта в качестве аргумента target, если таковой имеется, с позиционными и ключевыми аргументами, взятыми из аргументов args и kwargs соответственно.Использование списка или кортежа в качестве аргумента args, переданного в
Thread, может достичь того же эффекта.Пример:
>>> from threading import Thread >>> t = Thread(target=print, args=[1]) >>> t.run() 1 >>> t = Thread(target=print, args=(1,)) >>> t.run() 1
-
join(timeout=None) -
Ожидать завершения потока. Это блокирует вызывающий поток до тех пор, пока поток, метод
join()которого вызывается, не завершится — либо нормально, либо через необработанное исключение — или пока не наступит необязательный таймаут.Если аргумент timeout присутствует и не
None, он должен быть числом с плавающей точкой, определяющим таймаут операции в секундах (или долях секунды). Так какjoin()всегда возвращаетNone, вам нужно вызватьis_alive()послеjoin(), чтобы определить, произошел ли таймаут — если поток все еще жив, вызовjoin()сработал в ограниченное время.Если аргумент timeout не присутствует или
None, операция будет заблокирована до завершения потока.Поток может быть присоединен много раз.
Метод
join()вызываетRuntimeError, если происходит попытка присоединить текущий поток, так как это приведет к тупиковой ситуации. Также возникает ошибка, если вы пытаетесьjoin()поток до его запуска, и попытка вызовет то же исключение.
-
name -
Строка, используемая только для идентификации. Она не имеет семантики. Несколько потоков могут иметь одинаковое имя. Начальное имя задается конструктором.
-
getName() -
setName() -
Устаревший API-интерфейс для получения/установки
name; вместо него используйте свойство напрямую.Устарело начиная с версии 3.10.
-
ident -
«Идентификатор потока» этого потока или
Noneесли поток не был запущен. Это целое число, отличное от нуля. См. функциюget_ident(). Идентификаторы потоков могут быть повторно использованы при выходе потока и создании другого. Идентификатор доступен даже после завершения потока.
-
native_id -
Идентификатор потока (
TID) этого потока, назначенный ОС (ядром). Это целое число, неотрицательное, илиNoneесли поток не был запущен. См. функциюget_native_id(). Это значение может быть использовано для уникальной идентификации этого потока во всей системе (до завершения потока, после чего значение может быть повторно использовано ОС).Примечание
Аналогично идентификаторам процессов, идентификаторы потоков действительны (гарантируют уникальность во всей системе) только с момента создания потока до его завершения.
Доступность: Windows, FreeBSD, Linux, macOS, OpenBSD, NetBSD, AIX, DragonFlyBSD.
Добавлена в версии 3.8.
-
is_alive() -
Возвращает, жив ли поток.
Этот метод возвращает
Trueсразу перед запуском методаrun()и сразу после завершения методаrun(). Модульная функцияenumerate()возвращает список всех живых потоков.
-
daemon -
Булево значение, указывающее, является ли этот поток демоническим потоком (
True) или нет (False). Это свойство должно быть установлено до вызоваstart(), в противном случае будет поднято исключениеRuntimeError. Его начальное значение наследуется от создающего потока; главный поток не является демоническим, поэтому все потоки, созданные в главном потоке, по умолчанию имеютdaemon=False.Весь интерпретатор Python завершает работу, когда не остается живых потоков, которые не являются демоническими.
-
isDaemon() -
setDaemon() -
Устаревший API-интерфейс для получения/установки
daemon; вместо него используйте свойство напрямую.Устарело начиная с версии 3.10.
-
Объекты блокировок
Примитивная блокировка — это примитив синхронизации, который не принадлежит конкретной нити при блокировке. В Python в настоящее время это примитив синхронизации самого низкого уровня, реализованный непосредственно модулем расширения _thread.
Примитивная блокировка находится в одном из двух состояний: «заблокировано» или «разблокировано». Она создается в состоянии «разблокировано». Она имеет два основных метода: acquire() и release(). Когда состояние «разблокировано», acquire() изменяет состояние на «заблокировано» и возвращает значение немедленно. Когда состояние «заблокировано», acquire() блокируется до тех пор, пока вызов release() в другой нити не изменит его на «разблокировано», затем вызов acquire() устанавливает его в «заблокировано» и возвращает значение. Метод release() следует вызывать только в состоянии «заблокировано»; он изменяет состояние на «разблокировано» и возвращает значение немедленно. Если попытка разблокировать разблокированную блокировку, будет поднято исключение RuntimeError.
Блокировки также поддерживают протокол управления контекстом протокол управления контекстом.
Когда более одной нити заблокированы в acquire() в ожидании изменения состояния на «разблокировано», только одна нить продолжает выполнение, когда вызов release() устанавливает состояние на «разблокировано»; какая из ожидающих нитей продолжит работу, не определено и может различаться в различных реализациях.
Все методы выполняются атомарно.
-
class threading.Lock -
Класс, реализующий объекты примитивных блокировок. После того, как нить приобрела блокировку, последующие попытки приобретения блокировки блокируют нить до тех пор, пока она не будет освобождена; любую нить может освободить её.
Обратите внимание, что
Lockфактически является функцией-фабрикой, которая возвращает экземпляр наиболее эффективной версии конкретного класса Lock, поддерживаемого платформой.-
acquire(blocking=True, timeout=- 1) -
Приобретение блокировки, блокирующее или неблокирующее.
При вызове с аргументом blocking, установленным в
True(по умолчанию), блокируется до тех пор, пока блокировка не будет разблокирована, затем устанавливается в «заблокировано» и возвращаетсяTrue.При вызове с аргументом blocking, установленным в
False, блокировка не происходит. Если вызов с blocking, установленным вTrue, заблокировал бы нить, тоFalseвозвращается немедленно; в противном случае, блокировка устанавливается в «заблокировано» и возвращаетсяTrue.При вызове с аргументом timeout, установленным в положительное значение с плавающей точкой, блокировка выполняется не более чем в течение указанного количества секунд, пока блокировка не может быть приобретена. Аргумент timeout со значением
-1указывает неограниченное ожидание. Запрещено указывать timeout, когда blocking равноFalse.Значение возврата —
Trueесли блокировка приобретена успешно,Falseв противном случае (например, если истекло время ожидания).Изменено в версии 3.2: Параметр timeout является новым.
Изменено в версии 3.2: Приобретение блокировки может теперь прерываться сигналами на POSIX, если реализация нитей поддерживает эту возможность.
-
release() -
Освобождение блокировки. Это можно вызвать из любой нити, а не только из той, которая приобрела блокировку.
Если блокировка заблокирована, её состояние сбрасывается на «разблокировано», и возвращается значение. Если другие нити заблокированы в ожидании разблокирования блокировки, то разрешается продолжить работу ровно одной из них.
Если вызывается на разблокированной блокировке, то поднимается исключение
RuntimeError.Значение возврата отсутствует.
-
locked() -
Возвращает
Trueесли блокировка приобретена.
-
Объекты повторно входящих блокировок
Повторно входящая блокировка — это примитив синхронизации, который может быть приобретен несколько раз одной и той же нитью. Внутренне она использует понятия «владеющая нить» и «уровень рекурсии» помимо состояния «заблокировано/разблокировано», используемого примитивными блокировками. В состоянии «заблокировано» какая-то нить владеет блокировкой; в состоянии «разблокировано» ни одна нить не владеет ею.
Для блокировки блокировки нить вызывает метод acquire(); он возвращает значение, когда нить владеет блокировкой. Для разблокировки блокировки нить вызывает метод release(). Вызовы acquire()/release() могут быть вложены; только последний вызов release() (вызов release() самого внешнего парного вызова) устанавливает блокировку в состояние «разблокировано» и позволяет другой нити, заблокированной в acquire(), продолжить работу.
Повторно входящие блокировки также поддерживают протокол управления контекстом протокол управления контекстом.
-
class threading.RLock -
Этот класс реализует объекты повторно входящих блокировок. Повторно входящая блокировка должна быть освобождена нитью, которая её приобрела. После того, как нить приобрела повторно входящую блокировку, та же нить может её повторно приобрести без блокировки; нить должна освободить её один раз для каждого раза, когда она её приобрела.
Обратите внимание, что
RLockфактически является функцией-фабрикой, которая возвращает экземпляр наиболее эффективной версии конкретного класса RLock, поддерживаемого платформой.-
acquire(blocking=True, timeout=- 1) -
Приобретение блокировки, блокирующее или неблокирующее.
При вызове без аргументов: если эта нить уже владеет блокировкой, уровень рекурсии увеличивается на единицу, и возвращается значение немедленно. В противном случае, если блокировка принадлежит другой нити, блокируется до тех пор, пока блокировка не будет разблокирована. После разблокирования блокировки (она не принадлежит ни одной нити), она приобретается, уровень рекурсии устанавливается в единицу, и возвращается значение. Если более одной нити заблокированы в ожидании разблокирования блокировки, только одна из них сможет получить владение блокировкой. В этом случае значение возврата отсутствует.
При вызове с аргументом blocking, установленным в
True, выполняется то же действие, что и при вызове без аргументов, и возвращаетсяTrue.При вызове с аргументом blocking, установленным в
False, блокировка не происходит. Если вызов без аргументов заблокировал бы нить, тоFalseвозвращается немедленно; в противном случае, выполняется то же действие, что и при вызове без аргументов, и возвращаетсяTrue.При вызове с аргументом timeout, установленным в положительное значение с плавающей точкой, блокировка выполняется не более чем в течение указанного количества секунд, пока блокировка не может быть приобретена. Возвращается
Trueесли блокировка приобретена,Falseесли истекло время ожидания.Изменено в версии 3.2: Параметр timeout является новым.
-
release() -
Освобождение блокировки, уменьшая уровень рекурсии. Если после уменьшения он равен нулю, блокировка сбрасывается в состояние «разблокировано» (не принадлежит ни одной нити), и если другие нити заблокированы в ожидании разблокирования блокировки, то ровно одна из них может продолжить работу. Если после уменьшения уровень рекурсии по-прежнему не равен нулю, блокировка остаётся заблокированной и принадлежит вызывающей нити.
Вызывайте этот метод только тогда, когда вызывающая нить владеет блокировкой. Если метод вызывается при разблокированной блокировке, поднимается исключение
RuntimeError.Значение возврата отсутствует.
-
Объекты условий
Переменная условия всегда связана с каким-либо замком; его можно передать в качестве аргумента, или он будет создан по умолчанию. Передача замка полезна, когда несколько переменных условия должны использовать один и тот же замок. Замок является частью объекта условия: вам не нужно отслеживать его отдельно.
Переменная условия подчиняется протоколу управления контекстом управления контекстом: использование оператора with приобретает связанный замок на время блока кода. Методы acquire() и release() также вызывают соответствующие методы связанного замка.
Другие методы должны вызываться, удерживая связанный замок. Метод wait() освобождает замок и затем блокируется до тех пор, пока другой поток не разбудит его, вызвав notify() или notify_all(). После пробуждения wait() повторно приобретает замок и возвращает значение.
Также можно указать таймаут.
Метод notify() разбуживает один из потоков, ожидающих переменную условия, если таковые имеются. Метод notify_all() разбуживает все потоки, ожидающие переменную условия.
Примечание: методы notify() и notify_all() не освобождают замок; это означает, что пробужденный поток или потоки не вернутся из вызова wait() сразу, а только когда поток, вызвавший notify() или notify_all(), в конечном итоге откажется от владения замком.
Типичный стиль программирования с использованием переменных условия использует замок для синхронизации доступа к некоторому общему состоянию; потоки, заинтересованные в конкретном изменении состояния, вызывают wait() многократно, пока не увидят желаемое состояние, в то время как потоки, изменяющие состояние, вызывают notify() или notify_all(), когда они изменяют состояние таким образом, что оно потенциально может быть желаемым состоянием для одного из ожидающих потоков. Например, следующий код представляет собой ситуацию «производитель-потребитель» с неограниченной емкостью буфера:
# Consume one item
with cv:
while not an_item_is_available():
cv.wait()
get_an_available_item()
# Produce one item
with cv:
make_an_item_available()
cv.notify()
Цикл while проверки условия приложения необходим, потому что wait() может вернуть значение после произвольно долгого времени, а условие, которое вызвало вызов notify(), может больше не выполняться. Это присуще многопоточному программированию. Метод wait_for() может быть использован для автоматизации проверки условия и упрощает вычисление таймаутов:
# Consume an item
with cv:
cv.wait_for(an_item_is_available)
get_an_available_item()
Чтобы выбрать между notify() и notify_all(), следует рассмотреть, интересно ли одно изменение состояния только для одного или нескольких ожидающих потоков. Например, в типичной ситуации «производитель-потребитель» добавление одного элемента в буфер требует разбудить только один поток-потребитель.
-
class threading.Condition(lock=None) -
Этот класс реализует объекты переменных условия. Переменная условия позволяет одному или нескольким потокам ждать, пока их не уведомит другой поток.
Если аргумент lock указан и не
None, он должен быть объектомLockилиRLock, и он используется в качестве базового замка. В противном случае создается и используется новый объектRLockв качестве базового замка.Изменено в версии 3.3: изменено с фабричной функции на класс.
-
acquire(*args) -
Получить базовый замок. Этот метод вызывает соответствующий метод на базовом замке; возвращаемое значение — то, что возвращает этот метод.
-
release() -
Освободить базовый замок. Этот метод вызывает соответствующий метод на базовом замке; возвращаемое значение отсутствует.
-
wait(timeout=None) -
Ждать уведомления или пока не произойдет истечение времени ожидания. Если вызывающий поток не получил замок, когда этот метод был вызван, будет возбуждено исключение
RuntimeError.Этот метод освобождает базовый замок, а затем блокируется, пока его не разбудит вызов
notify()илиnotify_all()для той же переменной условия в другом потоке, или пока не истечет время ожидания. После пробуждения или истечения времени ожидания он снова получает замок и возвращается.Когда аргумент timeout присутствует и не
None, он должен быть числом с плавающей точкой, задающим время ожидания операции в секундах (или их долях).Когда базовый замок является
RLock, он не освобождается с помощью методаrelease(), так как это может не фактически разблокировать замок, когда он был получен многократно рекурсивно. Вместо этого используется внутренний интерфейс классаRLock, который действительно его разблокирует, даже если он был получен рекурсивно несколько раз. Затем используется другой внутренний интерфейс для восстановления уровня рекурсии, когда замок снова приобретается.Возвращаемое значение —
True, если не истекло заданное время ожидания timeout, в противном случае —False.Изменено в версии 3.2: Ранее метод всегда возвращал
None.
-
wait_for(predicate, timeout=None) -
Ждать, пока условие не станет истинным. predicate должен быть вызываемым объектом, результат которого будет интерпретироваться как булево значение. Может быть предоставлено timeout, задающее максимальное время ожидания.
Этот вспомогательный метод может вызывать
wait()многократно, пока условие не будет выполнено или не истечет время ожидания. Возвращаемое значение — последнее возвращаемое значение предиката и будет равноFalseв случае истечения времени ожидания.Без учета функции таймаута вызов этого метода примерно эквивалентен написанию:
while not predicate(): cv.wait()Поэтому применяются те же правила, что и для
wait(): замок должен быть получен при вызове и снова приобретается по возвращении. Предикат оценивается при удержании замка.Добавлен в версии 3.2.
-
notify(n=1) -
По умолчанию разбудить один ожидающий поток по этому условию, если таковой есть. Если вызывающий поток не получил замок, когда этот метод был вызван, будет возбуждено исключение
RuntimeError.Этот метод разбудит не более n потоков, ожидающих переменной условия; это бесполезно, если ожидающих потоков нет.
Текущая реализация разбудит ровно n потоков, если ожидающих потоков по крайней мере n. Однако нельзя полагаться на это поведение. Будущая оптимизированная реализация может иногда разбудить больше, чем n потоков.
Примечание: разбуженный поток не вернётся из вызова
wait()до тех пор, пока не сможет получить замок. Так какnotify()не освобождает замок, его вызывающий должен.
-
notify_all() -
Разбудить все ожидающие потоки по этому условию. Этот метод действует как
notify(), но разбудит все ожидающие потоки вместо одного. Если вызывающий поток не получил замок, когда этот метод был вызван, будет возбуждено исключениеRuntimeError.Метод
notifyAllявляется устаревшим псевдонимом для этого метода.
-
Объекты семафоров
Это одна из старейших примитивов синхронизации в истории информатики, изобретённая голландским компьютерным учёным Эдсгером В. Дейкстрой (он использовал имена P() и V() вместо acquire() и release()).
Семафор управляет внутренним счётчиком, который уменьшается при каждом вызове acquire() и увеличивается при каждом вызове release(). Счётчик никогда не может опуститься ниже нуля; когда acquire() обнаруживает, что он равен нулю, он блокируется, ожидая, пока какая-то другая нить не вызовет release().
Семафоры также поддерживают протокол управления контекстом.
-
class threading.Semaphore(value=1) -
Этот класс реализует объекты семафоров. Семафор управляет атомным счётчиком, представляющим количество вызовов
release()минус количество вызововacquire(), плюс начальное значение. Методacquire()блокируется, если необходимо, пока он не сможет вернуть значение, не сделав счётчик отрицательным. Если не указано, value по умолчанию равно 1.Необязательный аргумент задаёт начальное значение для внутреннего счётчика; он по умолчанию равен
1. Если заданное значение меньше 0, возникаетValueError.Изменено в версии 3.3: изменено с фабричной функции на класс.
-
acquire(blocking=True, timeout=None) -
Получить семафор.
При вызове без аргументов:
- Если внутренний счётчик больше нуля при входе, уменьшите его на единицу и верните
Trueнемедленно. - Если внутренний счётчик равен нулю при входе, заблокируйтесь, пока не разблокируетесь вызовом
release(). После разблокировки (и счётчик больше 0), уменьшите счётчик на 1 и вернитеTrue. Ровно одна нить будет разблокирована при каждом вызовеrelease(). Порядок, в котором нити разблокируются, не гарантируется.
При вызове с blocking, установленным в
False, не блокироваться. Если вызов без аргумента заблокируется, вернитеFalseнемедленно; в противном случае выполните то же, что и при вызове без аргументов, и вернитеTrue.При вызове с timeout, отличным от
None, он будет блокироваться не более чем в течение timeout секунд. Если приобретение не завершится успешно в этом интервале, вернитеFalse. ВернитеTrueв противном случае.Изменено в версии 3.2: Параметр timeout новый.
- Если внутренний счётчик больше нуля при входе, уменьшите его на единицу и верните
-
release(n=1) -
Освободить семафор, увеличив внутренний счётчик на n. Когда он был равен нулю при входе и другие нити ожидают, пока он станет больше нуля снова, разблокировать n из этих нитей.
Изменено в версии 3.9: Добавлен параметр n для одновременного разблокирования нескольких ожидающих нитей.
-
-
class threading.BoundedSemaphore(value=1) -
Класс, реализующий объекты семафоров с ограниченным числом. Семафор с ограниченным числом проверяет, чтобы его текущее значение не превышало его начального значения. Если это произойдёт, будет поднято исключение
ValueError. В большинстве ситуаций семафоры используются для защиты ресурсов с ограниченной ёмкостью. Если семафор слишком много раз освобождается, это признак ошибки. Если не указано, value по умолчанию равно 1.Изменено в версии 3.3: изменено с фабричной функции на класс.
Semaphore Пример
Семафоры часто используются для защиты ресурсов с ограниченной ёмкостью, например, сервера базы данных. В любой ситуации, где размер ресурса фиксирован, вы должны использовать семафор с ограниченным числом. Перед запуском рабочих нитей ваша основная нить инициализирует семафор:
maxconnections = 5 # ... pool_sema = BoundedSemaphore(value=maxconnections)
После запуска рабочие нити вызывают методы acquire и release семафора, когда им нужно подключиться к серверу:
with pool_sema:
conn = connectdb()
try:
# ... use connection ...
finally:
conn.close()
Использование семафора с ограниченным числом снижает вероятность того, что ошибка программирования, которая приводит к освобождению семафора больше, чем его приобретение, останется незамеченной.
Объекты событий
Это одна из самых простых механизмов для коммуникации между нитями: одна нить сигнализирует об событии, а другие нити ждут его.
Объект события управляет внутренним флагом, который может быть установлен в true методом set() и сброшен в false методом clear(). Метод wait() блокируется, пока флаг не станет истинным.
-
class threading.Event -
Класс, реализующий объекты событий. Событие управляет флагом, который может быть установлен в true методом
set()и сброшен в false методомclear(). Методwait()блокируется, пока флаг не станет истинным. Флаг изначально false.Изменено в версии 3.3: изменено с фабричной функции на класс.
-
is_set() -
Возвращает
Trueтогда и только тогда, когда внутренний флаг равен true.Метод
isSetявляется устаревшим алиасом для этого метода.
-
set() -
Установить внутренний флаг в true. Все нити, ожидающие, пока он станет истинным, пробуждаются. Нити, которые вызывают
wait()после того, как флаг стал истинным, не будут блокироваться.
-
clear() -
Сбросить внутренний флаг в false. Впоследствии нити, вызывающие
wait(), будут блокироваться, покаset()не вызовет установку внутреннего флага в true снова.
-
wait(timeout=None) -
Заблокировать, пока внутренний флаг не станет true. Если внутренний флаг равен true при входе, верните значение немедленно. В противном случае заблокируйтесь, пока другая нить не вызовет
set()для установки флага в true или пока не наступит заданный таймаут.Когда аргумент таймаута присутствует и не равен
None, он должен быть числом с плавающей точкой, задающим таймаут операции в секундах (или их долях).Этот метод возвращает
Trueтогда и только тогда, когда внутренний флаг был установлен в true, либо до вызова wait, либо после его начала, поэтому он всегда возвращаетTrue, за исключением случая, когда задан таймаут и операция истекла.Изменено в версии 3.1: Ранее метод всегда возвращал
None.
-
Объекты таймеров
Этот класс представляет собой действие, которое должно быть выполнено только после определенного периода времени — таймер. Timer является подклассом Thread и как таковой также служит примером создания пользовательских потоков.
Таймеры запускаются, как и потоки, путем вызова их метода Timer.start. Таймер можно остановить (до начала его действия) с помощью метода cancel(). Интервал, в течение которого таймер будет ожидать перед выполнением своего действия, может не совпадать точно с интервалом, указанным пользователем.
Например:
def hello():
print("hello, world")
t = Timer(30.0, hello)
t.start() # after 30 seconds, "hello, world" will be printed
-
class threading.Timer(interval, function, args=None, kwargs=None) -
Создайте таймер, который выполнит function с аргументами args и ключевыми аргументами kwargs после того, как пройдет interval секунд. Если args является
None(по умолчанию), то будет использоваться пустой список. Если kwargs являетсяNone(по умолчанию), то будет использоваться пустой словарь.Изменено в версии 3.3: изменено с фабричной функции на класс.
-
cancel() -
Остановите таймер и отменить выполнение действия таймера. Это сработает только если таймер все еще находится на стадии ожидания.
-
Объекты барьеров
Введено в версии 3.2.
Этот класс предоставляет простую синхронизационную примитив для использования фиксированным числом потоков, которые нуждаются в ожидании друг друга. Каждый из потоков пытается пройти барьер, вызывая метод wait(), и будет блокирован до тех пор, пока все потоки не выполнят вызовы wait(). В этот момент потоки одновременно освобождаются.
Барьер может быть повторно использован любое количество раз для одинакового количества потоков.
В качестве примера, вот простой способ синхронизации потока клиента и сервера:
b = Barrier(2, timeout=5)
def server():
start_server()
b.wait()
while True:
connection = accept_connection()
process_server_connection(connection)
def client():
b.wait()
while True:
connection = make_connection()
process_client_connection(connection)
-
class threading.Barrier(parties, action=None, timeout=None) -
Создайте объект барьера для parties количества потоков. Функция action, если она предоставлена, - это вызываемая функция, которая будет вызвана одним из потоков, когда они будут освобождены. timeout - значение таймаута по умолчанию, если он не указан для метода
wait().-
wait(timeout=None) -
Пройти барьер. Когда все потоки, участвующие в барьере, вызовут эту функцию, они все будут освобождены одновременно. Если предоставлен timeout, он используется вместо того, который был предоставлен в конструкторе класса.
Возвращаемое значение — целое число в диапазоне от 0 до parties – 1, разное для каждого потока. Это можно использовать для выбора потока для выполнения специальной работы, например:
i = barrier.wait() if i == 0: # Only one thread needs to print this print("passed the barrier")Если в конструктор была передана функция action, один из потоков её вызовет перед тем, как быть освобождённым. Если при этом произойдет ошибка, барьер переходит в состояние ошибки.
Если вызов истечёт по таймауту, барьер переходит в состояние ошибки.
Этот метод может вызвать исключение
BrokenBarrierError, если барьер сломан или сброшен, пока поток ждёт.
-
reset() -
Возвращает барьер в исходное, пустое состояние. Любые потоки, ожидающие его, получат исключение
BrokenBarrierError.Обратите внимание, что использование этой функции может потребовать внешней синхронизации, если есть другие потоки, состояние которых неизвестно. Если барьер сломан, лучше оставить его и создать новый.
-
abort() -
Переводит барьер в состояние ошибки. Это заставляет все активные или будущие вызовы
wait()завершиться ошибкой с исключениемBrokenBarrierError. Используйте это, например, если один из потоков должен прерваться, чтобы избежать тупиковой ситуации в приложении.Может быть предпочтительнее просто создать барьер с разумным значением timeout, чтобы автоматически защититься от сбоев одного из потоков.
-
parties -
Количество потоков, необходимых для прохождения барьера.
-
n_waiting -
Количество потоков, в данный момент ожидающих в барьере.
-
broken -
Булево значение, равное
Trueесли барьер находится в состоянии ошибки.
-
-
exception threading.BrokenBarrierError -
Это исключение, подкласс
RuntimeError, возникает, когда объектBarrierсброшен или сломан.
Использование блокировок, условий и семафоров в операторе with
Все объекты, предоставляемые этим модулем, имеющие методы acquire и release, могут использоваться в качестве менеджеров контекста для оператора with. Метод acquire будет вызван при входе в блок, а release - при выходе из блока. Таким образом, следующий фрагмент:
with some_lock:
# do something...
эквивалентен:
some_lock.acquire()
try:
# do something...
finally:
some_lock.release()
В настоящее время объекты Lock, RLock, Condition, Semaphore и BoundedSemaphore могут использоваться в качестве менеджеров контекста оператора with.
© 2001–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.11/library/threading.html