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. Однако, потоки всё ещё являются подходящей моделью, если вы хотите одновременно запускать несколько задач, связанных с вводом-выводом.
Этот модуль определяет следующие функции:
-
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, системы с POSIX-потоками.
В этом модуле также определена следующая константа:
-
threading.TIMEOUT_MAX -
Максимальное значение, разрешённое для параметра timeout блокирующих функций (
Lock.acquire(),RLock.acquire(),Condition.wait()и т. д.). Указание значения таймаута, большего этого значения, приведёт к генерации исключенияOverflowError.Новое в версии 3.2.
В этом модуле определено несколько классов, подробное описание которых приведено в разделах ниже.
Структура этого модуля в общих чертах основана на модели потоков Java. Однако в Java блокировки и переменные состояния являются базовым поведением каждого объекта, а в Python они являются отдельными объектами. Класс Python Thread поддерживает подмножество поведения класса Thread в Java; в настоящее время приоритеты отсутствуют, нет групп потоков, а потоки нельзя уничтожить, остановить, приостановить, возобновить или прервать. Статические методы класса Thread Java, когда они реализованы, отображаются в функции уровня модуля.
Все описанные ниже методы выполняются атомарно.
Данные локальные для потока
Данные локальные для потока — это данные, значения которых специфичны для каждого потока. Для управления данными локальными для потока просто создайте экземпляр local (или подкласс) и сохраните атрибуты в нём:
mydata = threading.local() mydata.x = 1
Значения экземпляра будут разными для разных потоков.
-
class threading.local -
Класс, представляющий данные локальные для потока.
Более подробную информацию и обширные примеры можно найти в документации модуля
_threading_local.
Объекты потока
Класс 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. Объекты потоков-заглушек имеют ограниченную функциональность; они всегда считаются активными и демон-потоками и не могут быть join()ed. Они никогда не удаляются, так как невозможно обнаружить завершение внешних потоков.
-
class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None) -
Этот конструктор всегда должен вызываться с ключевыми аргументами. Аргументы:
group должен быть
None; зарезервирован для будущего расширения, когда реализован классThreadGroup.target — вызываемый объект, который будет вызван методом
run(). По умолчаниюNone, то есть ничего не вызывается.name — имя потока. По умолчанию генерируется уникальное имя в формате «Поток-N», где N — небольшое десятичное число, или «Поток-N (цель)», где «цель» —
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 соответственно.
-
join(timeout=None) -
Подождать завершения потока. Этот метод блокирует вызывающий поток до тех пор, пока поток, метод
join()которого вызывается, не завершится — либо нормально, либо из-за необработанного исключения — или пока не произойдёт заданный таймаут.Когда аргумент timeout присутствует и не
None, он должен быть числом с плавающей точкой, определяющим таймаут операции в секундах (или долях секунды). Так какjoin()всегда возвращаетNone, вам необходимо вызватьis_alive()послеjoin(), чтобы определить, произошёл ли таймаут — если поток всё ещё жив, вызовjoin()истек по таймауту.Когда аргумент timeout не указан или
None, операция будет блокироваться до завершения потока.Поток можно
join()много раз.join()генерирует исключениеRuntimeError, если попытка объединения текущего потока, так как это приведет к тупику. Также ошибка вызыватьjoin()поток до его запуска, попытка сделать это вызывает то же самое исключение.
-
name -
Строка, используемая только для идентификации. Она не имеет семантики. Несколько потоков могут иметь одинаковое имя. Начальное имя устанавливается конструктором.
-
getName() -
setName() -
Устаревший API для получения/установки
name; используйте его непосредственно как свойство вместо него.Устарело начиная с версии 3.10.
-
ident -
Идентификатор потока или
Noneесли поток ещё не запущен. Это целое число, отличное от нуля. См. функциюget_ident(). Идентификаторы потоков могут быть переиспользованы, когда поток завершается, а создаётся другой. Идентификатор доступен даже после завершения потока.
-
native_id -
Идентификатор потока (
TID) этого потока, присвоенный операционной системой (ядром). Это целое неотрицательное число илиNoneесли поток ещё не запущен. См. функциюget_native_id(). Это значение может использоваться для уникальной идентификации этого конкретного потока в системе (до завершения потока, после чего значение может быть переиспользовано ОС).Примечание
Подобно идентификаторам процессов, идентификаторы потоков действительны (гарантированно уникальны в системе) только с момента создания потока до его завершения.
Доступность: Требуется функция
get_native_id().Введено в версии 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, и до тех пор, пока блокировка не может быть получена. Аргумент timeout со значением
-1указывает неограниченное ожидание. Запрещается указывать timeout, когда blocking равноFalse.Значение возврата равно
Trueесли блокировка получена успешно,Falseесли нет (например, если timeout истек).Изменено в версии 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 установленным в положительное значение, заблокироваться на самое большое количество секунд, указанное в 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до тех пор, пока не истечёт заданный таймаут, в этом случае —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()).
Семафор управляет внутренней переменной-счётчиком, которая уменьшается на 1 при каждом вызове acquire() и увеличивается на 1 при каждом вызове release(). Счётчик никогда не может стать меньше нуля; когда acquire() обнаруживает, что он равен нулю, он блокируется, ожидая, пока другая нить не вызовет release().
Семафоры также поддерживают протокол управления контекстом.
-
class threading.Semaphore(value=1) -
Этот класс реализует объекты семафоров. Семафор управляет атомарным счётчиком, представляющим количество вызовов
release()минус количество вызововacquire(), плюс начальное значение. Методacquire()блокируется при необходимости, пока не сможет вернуть значение без понижения счётчика до отрицательного. Если не указано, value по умолчанию равно 1.Необязательный аргумент задаёт начальное значение для внутреннего счётчика; по умолчанию он равен
1. Если заданное значение меньше 0, возникает исключениеValueError.Изменено в версии 3.3: изменено с функции-конструктора на класс.
-
acquire(blocking=True, timeout=None) -
Получить семафор.
При вызове без аргументов:
- Если внутренний счётчик больше нуля при входе, уменьшите его на 1 и верните
Trueнемедленно. - Если внутренний счётчик равен нулю при входе, заблокируйтесь до пробуждения вызовом
release(). После пробуждения (и счётчик больше 0), уменьшите счётчик на 1 и вернитеTrue. Ровно одна нить будет разбужена каждым вызовомrelease(). Порядок пробуждения нитей не гарантируется.
При вызове с blocking, установленным в
False, не блокировать. Если вызов без аргумента заблокирует, вернитеFalseнемедленно; в противном случае сделайте то же самое, что и при вызове без аргументов, и вернитеTrue.При вызове с timeout, отличным от
None, он будет заблокирован не более чем на timeout секунд. Если acquire не выполнится успешно в течение этого интервала, вернитеFalse. В противном случае вернитеTrue.Изменено в версии 3.2: Параметр timeout новый.
- Если внутренний счётчик больше нуля при входе, уменьшите его на 1 и верните
-
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()
Использование ограниченного семафора уменьшает вероятность того, что ошибка программирования, которая приводит к тому, что семафор освобождается чаще, чем приобретается, останется незамеченной.
Объекты событий
Это один из самых простых механизмов коммуникации между нитями: одна нить сигнализирует об событии, а другие нити ожидают его.
Объект события управляет внутренней меткой, которая может быть установлена в истинное значение методом set() и сброшена в ложное методом clear(). Метод wait() блокируется до тех пор, пока метка не станет истинной.
-
class threading.Event -
Класс, реализующий объекты событий. Событие управляет флагом, который может быть установлен в истинное значение методом
set()и сброшен в ложное значение методомclear(). Методwait()блокируется до тех пор, пока флаг не станет истинным. Флаг изначально ложный.Изменено в версии 3.3: изменено с функции-конструктора на класс.
-
is_set() -
Возвращает
Trueтогда и только тогда, когда внутренний флаг равен true.Метод
isSet— устаревший псевдоним для этого метода.
-
set() -
Установить внутренний флаг в истинное значение. Все нити, ожидающие, пока он станет истинным, пробуждаются. Нити, вызывающие
wait()после того, как флаг станет истинным, не будут блокироваться.
-
clear() -
Сбросить внутренний флаг в ложное значение. После этого нити, вызывающие
wait(), будут блокироваться до тех пор, пока методset()не вызовут для установки внутреннего флага в истинное значение снова.
-
wait(timeout=None) -
Заблокироваться до тех пор, пока внутренний флаг не станет истинным. Если внутренний флаг равен true при входе, вернитесь немедленно. В противном случае, заблокируйтесь до тех пор, пока другая нить не вызовет
set()для установки флага в истинное значение, или пока не наступит заданный таймаут.Если аргумент timeout присутствует и не равен
None, он должен быть числом с плавающей точкой, задающим таймаут операции в секундах (или долях секунды).Этот метод возвращает
Trueтогда и только тогда, когда внутренний флаг был установлен в истинное значение, либо до вызова wait, либо после его начала, поэтому он всегда возвращаетTrueза исключением случая, когда задан таймаут, и операция истекает.Изменено в версии 3.1: Ранее метод всегда возвращал
None.
-
Объекты таймеров
Этот класс представляет собой действие, которое должно быть выполнено только после истечения определенного промежутка времени — таймер. Timer является подклассом Thread и, как таковой, также служит примером создания пользовательских потоков.
Таймеры запускаются, как и потоки, вызовом их метода 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.10/library/threading.html