17.9. _thread – Низкоуровневый API потоков¶_thread – Low-level threading API
Этот модуль предоставляет низкоуровневые примитивы для работы с несколькими потоками (также называемыми легковесными процессами или задачами) – множеством потоков управления, разделяющих общее пространство данных. Для синхронизации предоставляются простые блокировки (также называемые мьютексами или двоичными семафорами). Модуль threading предоставляет более простой и высокоуровневый API для работы с потоками, построенный на основе этого модуля.
Модуль является опциональным. Он поддерживается в Windows, Linux, SGI IRIX, Solaris
2.x, а также в системах, имеющих реализацию POSIX-потоков (также известных как «pthread»).
Для систем, в которых отсутствует модуль _thread, доступен модуль _dummy_thread.
Он дублирует интерфейс данного модуля
и может использоваться в качестве замены «на лету».
Он определяет следующие константы и функции:
-
exception
_thread.error¶ Возникает при ошибках, связанных с потоками.
Изменено в версии 3.3: Теперь это синоним встроенного
RuntimeError.
-
_thread.LockType¶ Это тип объектов блокировки.
-
_thread.start_new_thread(function, args[, kwargs])¶ Запускает новый поток и возвращает его идентификатор. Поток выполняет функцию function со списком аргументов args (который должен быть кортежем). Необязательный аргумент kwargs задаёт словарь именованных аргументов. Когда функция возвращает управление, поток беззвучно завершается. Когда функция завершается из-за необработанного исключения, печатается трассировка стека, и поток завершается (но остальные потоки продолжают работу).
-
_thread.interrupt_main()¶ Возбуждает исключение
KeyboardInterruptв главном потоке. Подпоток может использовать эту функцию, чтобы прервать главный поток.
-
_thread.exit()¶ Вызывает исключение
SystemExit. Если оно не перехвачено, поток завершится без уведомления.
-
_thread.allocate_lock()¶ Возвращает новый объект блокировки. Методы блокировок описаны ниже. Изначально блокировка не установлена.
-
_thread.get_ident()¶ Возвращает «идентификатор потока» текущего потока. Это ненулевое целое число. Его значение не имеет прямого смысла; оно предназначено в качестве «магического ключа» для использования, например, в качестве индекса в словаре данных, специфичных для потока. Идентификаторы потоков могут быть повторно использованы после завершения потока и создания другого.
-
_thread.stack_size([size])¶ Возвращает размер стека потока, используемый при создании новых потоков. Необязательный аргумент size задаёт размер стека для последующих создаваемых потоков и должен быть 0 (использовать платформенное или сконфигурированное значение по умолчанию) или положительным целым числом не менее 32 768 (32 КиБ). Если size не указан, используется 0. Если изменение размера стека потока не поддерживается, возбуждается исключение
RuntimeError. Если указан недопустимый размер стека, возбуждается исключениеValueError, а размер стека не изменяется. В настоящее время 32 КиБ – минимальное поддерживаемое значение размера стека, достаточное для обеспечения пространства для самого интерпретатора. Обратите внимание, что некоторые платформы могут накладывать особые ограничения на значения размера стека, например, требовать минимальный размер стека > 32 КиБ или выделение памяти, кратное размеру страницы системной памяти – для получения дополнительных сведений следует обращаться к документации платформы (обычно страницы имеют размер 4 КиБ; если нет более точной информации, рекомендуется выбирать размер стека, кратный 4096). Доступность: Windows, системы с POSIX-потоками.
-
_thread.TIMEOUT_MAX¶ Максимальное допустимое значение параметра timeout для
Lock.acquire(). Указание тайм-аута, превышающего это значение, приведёт к возбуждениюOverflowError.Новое в версии 3.2.
Объекты блокировки имеют следующие методы:
-
lock.acquire(waitflag=1, timeout=-1)¶ Без необязательных аргументов этот метод захватывает блокировку безусловно, при необходимости ожидая, пока она не будет освобождена другим потоком (только один поток за раз может захватить блокировку – в этом и состоит их смысл).
Если целочисленный аргумент waitflag присутствует, действие зависит от его значения: если он равен нулю, блокировка захватывается, только если её можно захватить немедленно без ожидания, тогда как если он не равен нулю, блокировка захватывается безусловно, как указано выше.
Если аргумент с плавающей точкой timeout присутствует и положителен, он задаёт максимальное время ожидания в секундах перед возвратом. Отрицательное значение аргумента timeout задаёт неограниченное ожидание. Нельзя указать timeout, если waitflag равен нулю.
Возвращаемое значение равно
True, если блокировка успешно захвачена, иFalseв противном случае.Изменено в версии 3.2: Параметр timeout является новым.
Изменено в версии 3.2: Захват блокировки теперь может прерываться сигналами на POSIX.
-
lock.release()¶ Освобождает блокировку. Блокировка должна быть захвачена ранее, но не обязательно тем же потоком.
-
lock.locked()¶ Возвращает состояние блокировки:
True, если она захвачена каким-либо потоком,Falseв противном случае.
В дополнение к этим методам объекты блокировки можно также использовать с помощью оператора with, например:
import _thread
a_lock = _thread.allocate_lock()
with a_lock:
print("a_lock is locked while this executes")
Предостережения:
Потоки странно взаимодействуют с прерываниями: исключение
KeyboardInterruptбудет получено произвольным потоком. (Когда модульsignalдоступен, прерывания всегда направляются в главный поток.)Вызов
sys.exit()или возбуждение исключенияSystemExitэквивалентно вызову_thread.exit().Невозможно прервать метод
acquire()для блокировки – исключениеKeyboardInterruptвозникнет после того, как блокировка будет захвачена.При завершении главного потока решение о том, будут ли существовать другие потоки, зависит от системы. В большинстве систем они уничтожаются без выполнения предложений
try…finallyили вызова деструкторов объектов.При завершении главного потока он не выполняет никакой обычной очистки (за исключением того, что предложения
try…finallyсоблюдаются), и стандартные файлы ввода-вывода не сбрасываются.