16.8. _thread – Низкоуровневый API для работы с потоками¶_thread – Low-level threading API
Этот модуль предоставляет низкоуровневые примитивы для работы с несколькими потоками (также называемыми легковесными процессами или задачами) – несколькими потоками управления, разделяющими общее пространство данных. Для синхронизации предоставляются простые блокировки (также называемые мьютексами или двоичными семафорами). Модуль threading предоставляет более простой и высокоуровневый API для работы с потоками, построенный на основе этого модуля.
Модуль необязателен. Он поддерживается на Windows, Linux, SGI IRIX, Solaris 2.x, а также на системах, в которых реализованы потоки POSIX (также известные как «pthread»). Для систем, в которых нет модуля _thread, доступен модуль _dummy_thread. Он повторяет интерфейс этого модуля и может использоваться в качестве его замены без изменений.
Он определяет следующие константу и функции:
- exception _thread.error¶
- Возникает при ошибках, связанных с потоками.
- _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 кБ). Если изменение размера стека потока не поддерживается, возбуждается ThreadError. Если указанный размер стека некорректен, возбуждается ValueError, а размер стека не изменяется. 32 кБ – это минимальный поддерживаемый размер стека, гарантирующий достаточное пространство для самого интерпретатора. Обратите внимание, что некоторые платформы могут накладывать особые ограничения на значения размера стека, например, требовать минимальный размер > 32 кБ или выделение памяти, кратное размеру страницы системной памяти – для получения дополнительных сведений следует обращаться к документации платформы (страницы по 4 кБ распространены; при отсутствии более точной информации рекомендуется использовать размер стека, кратный 4096). Доступность: Windows, системы с потоками POSIX.
Объекты блокировки имеют следующие методы:
- lock.acquire([waitflag])¶
- Без необязательного аргумента этот метод захватывает блокировку безусловно, при необходимости ожидая, пока она не будет освобождена другим потоком (только один поток в единицу времени может захватить блокировку – в этом и состоит смысл их существования). Если присутствует целочисленный аргумент waitflag, действие зависит от его значения: если он равен нулю, блокировка захватывается только в том случае, если её можно захватить немедленно без ожидания; если же он не равен нулю, блокировка захватывается безусловно, как и раньше. Возвращаемое значение – True, если блокировка успешно захвачена, и False в противном случае.
- 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().
Не все встроенные функции, которые могут блокироваться в ожидании ввода-вывода, позволяют выполняться другим потокам. (Самые популярные из них (time.sleep(), file.read(), select.select()) работают как и ожидается.)
Невозможно прервать метод acquire() блокировки – исключение KeyboardInterrupt возникнет после того, как блокировка будет захвачена.
Когда основной поток завершается, выживание остальных потоков определяется системой. В SGI IRIX с собственной реализацией потоков они выживают. В большинстве других систем они уничтожаются без выполнения блоков try … finally и без вызова деструкторов объектов.
Когда главный поток завершается, он не выполняет обычные действия по очистке (за исключением того, что предложения try ... finally выполняются), и стандартные файлы ввода-вывода не сбрасываются.