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. Однако, потоки всё ещё являются подходящей моделью, если вы хотите одновременно выполнять несколько задач ввода/вывода.
Доступность: не WASI.
Этот модуль не работает или недоступен на WebAssembly. См. Платформы 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, DragonFlyBSD, GNU/kFreeBSD.
Добавлен в версии 3.8.
Изменено в версии 3.13: Добавлена поддержка GNU/kFreeBSD.
-
threading.enumerate() -
Возвращает список всех активных объектов
Thread. Список включает демонические потоки и объекты потоков-заглушек, созданныеcurrent_thread(). Он исключает завершённые потоки и потоки, которые ещё не были запущены. Однако основной поток всегда входит в результат, даже если он завершён.
-
threading.main_thread() -
Возвращает основной объект
Thread. В нормальных условиях основной поток — это поток, из которого был запущен интерпретатор Python.Добавлен в версии 3.4.
-
threading.settrace(func) -
Устанавливает функцию отслеживания для всех потоков, запущенных из модуля
threading. Функция func будет переданаsys.settrace()для каждого потока перед вызовом методаrun().
-
threading.settrace_all_threads(func) -
Устанавливает функцию отслеживания для всех потоков, запущенных из модуля
threading, и всех текущих потоков Python.Функция func будет передана
sys.settrace()для каждого потока перед вызовом методаrun().Добавлен в версии 3.12.
-
threading.gettrace() -
Получает функцию отслеживания, установленную с помощью
settrace().Добавлен в версии 3.10.
-
threading.setprofile(func) -
Установите функцию профилирования для всех потоков, запущенных из модуля
threading. Функция func будет передана вsys.setprofile()для каждого потока перед вызовом его методаrun().
-
threading.setprofile_all_threads(func) -
Установите функцию профилирования для всех потоков, запущенных из модуля
threading, и всех текущих потоков Python.Функция func будет передана в
sys.setprofile()для каждого потока перед вызовом его методаrun().Добавлена в версии 3.12.
-
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()и т. д.). Указание значения timeout, большего этого значения, вызоветOverflowError.Добавлена в версии 3.2.
Этот модуль определяет ряд классов, подробное описание которых приведено в разделах ниже.
Конструкции данного модуля в общих чертах основаны на модели потоков Java. Однако в Java блокировки и условия являются базовым поведением каждого объекта, а в Python они являются отдельными объектами. Класс Thread Python поддерживает подмножество поведения класса Thread Java; в настоящее время нет приоритетов, нет групп потоков и потоки не могут быть уничтожены, остановлены, приостановлены, возобновлены или прерваны. Статические методы класса Thread Java, когда они реализованы, отображаются на функции уровня модуля.
Все методы, описанные ниже, выполняются атомарно.
Данные, локальные для потока
Данные, локальные для потока, — это данные, значения которых специфичны для потока. Для управления данными, локальными для потока, просто создайте экземпляр 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 — имя потока. По умолчанию генерируется уникальное имя в формате «Поток-N», где N — небольшое десятичное число, или «Поток-N (цель)», где «цель» —
target.__name__, если указан аргумент target.args — список или кортеж аргументов для вызова целевого объекта. По умолчанию —
().kwargs — словарь ключевых аргументов для вызова целевого объекта. По умолчанию —
{}.Если не
None, daemon явно устанавливает, является ли поток демоническим. ЕслиNone(по умолчанию), свойство daemon наследуется от текущего потока.Если подкласс переопределяет конструктор, он должен убедиться, что вызывает конструктор базового класса (
Thread.__init__()) перед любыми другими действиями с потоком.Изменено в версии 3.3: Добавлен параметр daemon.
Изменено в версии 3.10: Используется имя target, если аргумент name опущен.
-
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, если есть попытка присоединиться к текущему потоку, так как это приведет к тупику. Также является ошибкой присоединение к потоку до его запуска, и попытки сделать это вызывают то же исключение.
-
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 -
Класс, реализующий примитивные объекты блокировок. После того, как поток получил блокировку, последующие попытки получить её блокируют выполнение, пока она не будет освобождена; любой поток может её освободить.
Изменено в версии 3.13:
Lockтеперь является классом. В более ранних версиях PythonLockбыла функцией-фабрикой, возвращающей экземпляр внутреннего закрытого типа блокировки.-
acquire(blocking=True, timeout=-1) -
Получить блокировку, блокирующим или неблокирующим способом.
При вызове с аргументом blocking установленным в
True(по умолчанию), заблокировать выполнение, пока блокировка не будет разблокирована, затем установить её в заблокированное состояние и вернутьTrue.При вызове с аргументом blocking установленным в
False, не блокировать выполнение. Если вызов с blocking, установленным вTrue, заблокирует выполнение, вернутьFalseнемедленно; в противном случае установить блокировку в заблокированное состояние и вернутьTrue.При вызове с аргументом timeout с плавающей точкой, установленным в положительное значение, заблокировать выполнение не более чем на заданное количество секунд параметром timeout, до тех пор, пока блокировка не будет получена. Значение timeout, равное
-1указывает на неограниченное ожидание. Запрещено указывать timeout, когда blocking равноFalse.Значение возврата равно
True, если блокировка получена успешно,Falseесли нет (например, если время ожидания истекло).Изменено в версии 3.2: Параметр timeout является новым.
Изменено в версии 3.2: Получение блокировки теперь может быть прервано сигналами в POSIX, если реализация потоков это поддерживает.
-
release() -
Освободить блокировку. Это может быть вызвано из любого потока, а не только из потока, который получил блокировку.
Если блокировка заблокирована, установить её в разблокированное состояние и вернуть значение. Если какие-либо другие потоки заблокированы, ожидая, пока блокировка станет разблокированной, позволить ровно одному из них продолжить работу.
При вызове на разблокированной блокировке, будет вызвано исключение
RuntimeError.Значение возврата отсутствует.
-
locked() -
Возвращает
True, если блокировка получена.
-
Объекты RLock
Повторно входящий замок — это примитив синхронизации, который может быть приобретён многократно одним и тем же потоком. Внутренне он использует понятия «владеющий поток» и «уровень рекурсии» в дополнение к состоянию заблокирован/разблокирован, используемому примитивными замками. В заблокированном состоянии замок владеет некоторый поток; в разблокированном состоянии им не владеет ни один поток.
Потоки вызывают метод acquire() замка для его блокировки и метод release() для его разблокировки.
Примечание
Повторно входящие замки поддерживают протокол управления контекстом, поэтому рекомендуется использовать with вместо ручного вызова acquire() и release() для обработки приобретения и освобождения замка для блока кода.
Вызовы acquire()/release() в RLock могут быть вложены, в отличие от вызовов acquire()/release() в Lock. Только последний release() (освобождение внешней пары) сбрасывает замок в разблокированное состояние и позволяет другому потоку, заблокированному в acquire(), продолжить выполнение.
Вызовы acquire()/release() должны использоваться парами: каждое приобретение должно иметь соответствующее освобождение в потоке, который его приобрел. Невызов освобождения столько раз, сколько замок был приобретён, может привести к тупику.
-
class threading.RLock -
Этот класс реализует объекты повторно входящих замков. Повторно входящий замок должен быть освобождён потоком, который его приобрел. После того, как поток приобрел повторно входящий замок, тот же поток может приобрести его снова без блокировки; поток должен освободить его один раз за каждый раз, когда он его приобретал.
Обратите внимание, что
RLockфактически является фабричной функцией, которая возвращает экземпляр наиболее эффективной версии конкретного класса RLock, поддерживаемого платформой.-
acquire(blocking=True, timeout=-1) -
Приобретение замка, блокирующее или неблокирующее.
См. также
- Использование RLock в качестве менеджера контекста
-
Рекомендуется использовать вместо ручных
acquire()иrelease()вызовов, когда это практически возможно.
При вызове с аргументом blocking установленным в
True(по умолчанию):- Если ни один поток не владеет замком, приобретает замок и возвращает значение сразу же.
- Если замок владеет другой поток, блокируется до момента, пока замок не будет приобретён, или до timeout, если он установлен в положительное значение с плавающей точкой.
- Если замок владеет тот же поток, снова приобретает замок и возвращает значение сразу же. Это отличие между
LockиRLock;Lockобрабатывает этот случай также, как и предыдущий, блокируясь до момента приобретения замка.
При вызове с аргументом blocking установленным в
False:- Если ни один поток не владеет замком, приобретает замок и возвращает значение сразу же.
- Если замок владеет другой поток, возвращает значение сразу же.
- Если замок владеет тот же поток, снова приобретает замок и возвращает значение сразу же.
Во всех случаях, если поток смог приобрести замок, возвращается
True. Если поток не смог приобрести замок (т. е. если не блокировка или истекло время ожидания), возвращаетсяFalse.Если вызывается несколько раз, не вызов
release()столько раз может привести к тупику. Рассмотрите использованиеRLockв качестве менеджера контекста вместо прямого вызова acquire/release.Изменено в версии 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()).
Семафор управляет внутренней счетной переменной, которая уменьшается на единицу при каждом вызове acquire() и увеличивается на единицу при каждом вызове release(). Счетчик никогда не может опуститься ниже нуля; когда acquire() обнаруживает, что он равен нулю, он блокируется, ожидая, пока какая-то другая нить не вызовет release().
Семафоры также поддерживают протокол управления контекстом.
-
class threading.Semaphore(value=1) -
Этот класс реализует объекты семафоров. Семафор управляет атомарной счетной переменной, представляющей разницу между числом вызовов
release()и числом вызововacquire(), плюс начальное значение. Методacquire()блокируется, если необходимо, пока он не сможет вернуть результат без понижения счетчика до отрицательного значения. Если не указано, значение по умолчанию для value равно 1.Необязательный аргумент задает начальное значение value для внутренней счетной переменной; по умолчанию оно равно
1. Если заданное значение value меньше 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() блокируется, пока метка не станет true.
-
class threading.Event -
Класс, реализующий объекты событий. Объект события управляет меткой, которая может быть установлена в true с помощью метода
set()и сброшена в false с помощью методаclear(). Методwait()блокируется, пока метка не станет true. Метка изначально равна false.Изменено в версии 3.3: изменено с фабричной функции на класс.
-
is_set() -
Возвращает
Trueтогда и только тогда, когда внутренняя метка равна true.Метод
isSet— это устаревшее алиас для этого метода.
-
set() -
Устанавливает внутреннюю метку в true. Все потоки, ожидающие, пока она не станет true, разблокируются. Потоки, которые вызывают
wait(), после того, как метка стала true, не будут блокироваться.
-
clear() -
Сбрасывает внутреннюю метку в false. В дальнейшем, потоки, вызывающие
wait(), будут блокироваться до тех пор, пока методset()не вызовет для установки внутренней метки в true снова.
-
wait(timeout=None) -
Блокирует выполнение, пока внутренняя метка равна false и тайм-аут, если задан, не истек. Значение возврата отражает причину возврата этого блокирующего метода;
Trueесли возвращение произошло, потому что внутренняя метка установлена в true, илиFalseесли задан тайм-аут и внутренняя метка не стала true в течение заданного времени ожидания.Если параметр тайм-аута присутствует и не равен
None, он должен быть числом с плавающей точкой, задающим тайм-аут операции в секундах или его долях.Изменено в версии 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–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/library/threading.html