В разделе рассмотрены функции модуля threading
, при помощи которых можно узнать общие сведения о потоках, запущенных в программе.
threading.active_count()
количество живых потоков,threading.current_thread()
текущий поток,threading.excepthook()
обрабатывает неперехваченные исключения в потоках,threading.get_ident()
идентификатор текущего потока,threading.get_native_id()
интегральный идентификатор текущего потока,threading.enumerate()
список объектов всех живых потоков,threading.main_thread()
объект основной потока,threading.TIMEOUT_MAX
максимально значение для тайм-аута блокировки.threading.active_count()
:Функция threading.active_count()
возвращает количество живых потоков - объектов threading.Thread()
. Возвращенное количество равно длине списка, возвращаемого функцией threading.enumerate()
.
import threading, time
def worker():
time.sleep(1)
for _ in range(6):
thread = threading.Thread(target=worker)
thread.start()
# использование 'threading.active_count()'
# 7 потоков = 6 порожденных + 1 основной
n_thread = threading.active_count()
print(n_thread)
# 7
threading.current_thread()
:Функция threading.current_thread()
возвращает текущий поток - объект threading.Thread()
, соответствующий потоку управления вызывающего объекта.
Если поток управления вызывающего объекта не был создан через модуль потоковой передачи, то возвращается фиктивный объект потока с ограниченной функциональностью.
import threading, time, logging
def worker():
# использование 'threading.current_thread()'
# получаем экземпляр Thread и атрибутом
# .name извлекаем имя потока
thread_name = threading.current_thread().name
logging.debug(f'Starting {thread_name}')
time.sleep(1)
logging.basicConfig(
level=logging.DEBUG,
format='[%(levelname)s] %(message)s',
)
th1 = threading.Thread(target=worker)
th1.start()
th2 = threading.Thread(name='worker', target=worker)
th2.start()
# [DEBUG] Starting Thread-1
# [DEBUG] Starting worker
threading.excepthook(args, /)
:Функция threading.excepthook()
обрабатывает неперехваченные исключения, вызванные в методе Thread.run()
.
Аргумент args имеет следующие атрибуты:
exc_type
: Тип исключения.exc_value
: Значение исключения, может быть None
.exc_traceback
: Трассировка исключения, может быть None
.thread
: Поток, который вызвал исключение, может быть None
.Если аргумент exc_type
это SystemExit
, то исключение игнорируется. В противном случае исключение выводится в sys.stderr
.
Если функция threading.excepthook()
вызывает исключение, то для его обработки вызывается sys.excepthook()
.
Функцию threading.excepthook()
можно переопределить, чтобы контролировать, как обрабатываются неперехваченные исключения, вызванные методом Thread.run()
.
Сохранение аргумента exc_value
с использованием пользовательского хука может создать ссылочный цикл. Его следует явно очистить, когда исключение больше не требуется.
Сохранение потока с использованием пользовательского хука может воскресить его, если он установлен на финализируемый объект. Чтобы избежать воскрешения объектов, избегайте сохранения потока после завершения пользовательского хука.
Смотрите также функцию sys.excepthook()
, которая обрабатывает неперехваченные исключения в однопоточных программах.
Новое в Python 3.8.
threading.get_ident()
:Функция threading.get_ident()
возвращает идентификатор текущего потока. Это ненулевое целое число.
Возвращаемое число не имеет прямого значения. Оно предназначено для использования в качестве "волшебного" файла cookie
, например для индексации словаря данных, специфичных для потока.
Идентификаторы потока могут быть повторно использованы при выходе из потока и создании другого потока.
import threading, time, logging
def worker():
name = threading.current_thread().name
# использование 'threading.get_ident()'
ident = threading.get_ident()
# тоже самое можно получить через атрибут
ident = threading.ident
logging.debug(f'Starting {name}, id: {ident}')
time.sleep(1)
logging.basicConfig(
level=logging.DEBUG,
format='[%(levelname)s] %(message)s',
)
for _ in range(3):
thread = threading.Thread(target=worker)
thread.start()
# [DEBUG] Starting Thread-1, id: 140190611068672
# [DEBUG] Starting Thread-2, id: 140190602675968
# [DEBUG] Starting Thread-3, id: 140190594283264
threading.get_native_id()
:Функция threading.get_native_id()
возвращает собственный интегральный идентификатор текущего потока, назначенный ядром. Это неотрицательное целое число.
Его значение может использоваться для уникальной идентификации этого конкретного потока в масштабах всей системы до тех пор, пока поток не завершится, после чего это значение может быть переработано ОС.
Пример получения собственного интегрального идентификатора такой же как у threading.get_ident()
Доступность: Windows, FreeBSD, Linux, macOS, OpenBSD, NetBSD, AIX.
Новое в Python 3.8.
threading.enumerate()
:Функция threading.enumerate()
возвращает список объектов threading.Thread()
всех живых потоков.
В список входят демонические потоки и объекты фиктивного потока плюс основной поток. В этот список не входят завершенные потоки и потоки, которые еще не были запущены.
import threading, time, logging
def worker():
time.sleep(1)
logging.basicConfig(
level=logging.DEBUG,
format='[%(levelname)s] %(message)s',
)
for _ in range(3):
thread = threading.Thread(target=worker)
thread.start()
# использование 'threading.enumerate()'
# проходимся по экземплярам 'Thread'
# и из которых атрибутом '.name'
# извлекаем имена живых потоков
for t in threading.enumerate():
logging.debug(f'Thread Name: {t.name}')
# [DEBUG] Thread Name: MainThread
# [DEBUG] Thread Name: Thread-1
# [DEBUG] Thread Name: Thread-2
# [DEBUG] Thread Name: Thread-3
threading.main_thread()
:Функция threading.main_thread()
возвращает объект основной потока.
В нормальных условиях основным потоком является поток, из которого был запущен интерпретатор Python.
import threading, time, logging
def worker():
name = threading.current_thread().name
time.sleep(1)
logging.debug(f'Ending {name}')
logging.basicConfig(
level=logging.DEBUG,
format='[%(levelname)s] %(message)s',
)
# использование 'threading.main_thread()'
# получаем экземпляр основного потока
main_thread = threading.main_thread()
# получаем имя основного потока
main_thread_name = main_thread.name
logging.debug(f'{main_thread_name} starting...')
for _ in range(3):
thread = threading.Thread(target=worker)
thread.start()
for t in threading.enumerate():
# Список 'threading.enumerate()' включает в себя основной
# поток и т.к. присоединение основного потока самого к себе
# приводит к тупиковой ситуации, то его необходимо пропустить
if t is main_thread:
continue
thead_name = t.name
logging.debug(f'{main_thread_name} joining {thead_name}')
t.join()
# [DEBUG] MainThread starting...
# [DEBUG] MainThread joining Thread-1
# [DEBUG] Ending Thread-1
# [DEBUG] MainThread joining Thread-2
# [DEBUG] Ending Thread-3
# [DEBUG] Ending Thread-2
# [DEBUG] MainThread joining Thread-3
threading.TIMEOUT_MAX
:Константа threading.TIMEOUT_MAX
представляет собой максимально допустимое значение для параметра тайм-аута функция блокировки (Lock.acquire()
, RLock.acquire()
, Condition.wait()
, и т. д.).
Указание времени ожидания, превышающее это значение будет вызывать исключение OverflowError
.
>>> import threading
>>> threading.TIMEOUT_MAX
# 9223372036.0