import threading th = threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
Конструктор threading.Thread()
всегда следует вызывать с ключевыми аргументами.
group=None
- зарезервировано для будущего расширения при реализации класса ThreadGroup
.target=None
- вызываемый объект (функция), который будет вызываться методом Thread.run()
. По умолчанию None
и означает, что ничего не вызывается.name=None
- имя потока. По умолчанию уникальное имя создается в форме "Thread-N", где N - небольшое десятичное число или с версии Python 3.10 Thread-N (target)
, где target
- это target.__ name__
, если конечно указан аргумент target
.args=()
- кортеж аргументов для вызываемого объекта target
. По умолчанию ()
kwargs={}
- словарь ключевых аргументов для вызываемого объекта target
. По умолчанию {}.daemon=None
- если аргумент daemon
не None
, то он явно устанавливает, является ли поток демоническим. Если daemon=None
(по умолчанию), то демоническое свойство наследуется от текущего потока.Если подкласс переопределяет конструктор, то он должен обязательно вызвать конструктор базового класса (Thread.__init__()
), прежде чем делать что-либо еще с потоком.
Класс Thread
модуля threading
запускает какое либо действие, которое будет выполняется в отдельном потоке управления.
Есть два способа запустить какое либо действие:
Thread.run()
в подклассе. Внимание! Никакие другие методы не должны переопределяться в подклассе (кроме конструктора). Другими словами, можно переопределять только методы __init__()
и Thread.run()
этого класса.
Как только объект потока создан, его деятельность должна быть запущена путем вызова метода потока Thread.start()
. Это вызывает метод Thread.run()
в отдельном потоке управления.
Как только активность потока запущена, он считается "живым". Поток перестает быть активным, когда его метод Thread.run()
завершается либо обычно, либо при возникновении необработанного исключения. Метод Thread.is_alive()
проверяет, жив ли поток.
Другие потоки могут вызывать метод Thread.join()
, который блокирует вызывающий поток до тех пор, пока не завершится поток, чей метод .join()
вызван. Например, если для всех порожденных программой потоков вызвать этот метод, то дальнейшее выполнение программы будет заблокировано до тех пор пока все потоки не завершатся.
У потока есть имя. Имя может быть передано конструктору (аргумент name
) и прочитано или изменено через атрибут Thread.name
.
Если метод Thread.run()
вызывает исключение, то для его обработки вызывается threading.excepthook()
. По умолчанию threading.excepthook()
молча игнорирует исключение SystemExit
.
Поток можно пометить как "демонический поток". Значение этого флага заключается в том, что когда программа Python завершается, работающими остаются только потоки демона. Начальное значение наследуется от создающего потока. Флаг можно установить с помощью свойства Thread.daemon
или аргумента конструктора daemon
.
Примечание. Потоки демона внезапно останавливаются при завершении работы. Их ресурсы (такие как открытые файлы, транзакции базы данных и т. д.) могут быть освобождены неправильно. Если необходимо, чтобы потоки корректно останавливались, то делайте их недемоническими и используйте подходящий механизм сигнализации, такой как объект threading.Event()
.
Существует объект основного потока программы. Основной поток соответствует начальному потоку управления в программе Python. Это не поток демона.
Существует вероятность того, что будут созданы "объекты фиктивного потока". Это объекты потоков, соответствующие "чужеродным потокам", которые представляют собой потоки управления, запускаемые вне модуля потоковой передачи, например непосредственно из кода языка C. Объекты фиктивного потока имеют ограниченную функциональность. Они всегда считаются живыми и демоническими и не могут быть объединены методом Thread.join()
. Они никогда не удаляются, так как невозможно обнаружить завершение чужих потоков.
Изменено в версии 3.10: если аргумент name
опущен, то используется имя функции target
.
Thread
.Thread.start()
запускает экземпляр Thread
,Thread.run()
представляет активность потока,Thread.join()
ждет, пока поток не завершится,Thread.name
имя потока,Thread.getName()
старый API getter
для атрибута name
,Thread.setName()
старый API setter
для атрибута name
,Thread.ident
идентификатор потока,Thread.native_id
интегральный идентификатор потока,Thread.is_alive()
сообщает, является ли поток живим,Thread.daemon
сообщает, является ли поток демоническим,Thread.isDaemon()
старый API для атрибута daemon
,Thread.setDaemon()
старый API для атрибута daemon
,Thread.start()
:Метод Thread.start()
запускает экземпляр Thread
в отдельном потоке управления.
Метод Thread.start()
должен вызываться не более одного раза для каждого объекта потока. Он обеспечивает вызов метода Thread.run()
объекта в отдельном потоке управления.
Метод вызовет исключение RuntimeError
, если будет вызван более одного раза для одного и того же объекта потока.
import threading, time def worker(num_thread): print(f'Старт потока №{num_thread}') time.sleep(1) print(f'Завершение работы потока №{num_thread}') for i in range(2): # создаем экземпляры 'Thread' с функцией # 'worker()', которая запустится в отдельных # трех потоках. Позиционные аргументы для # функции 'worker()' передаются в кортеже `args` thread = threading.Thread(target=worker, args=(i,)) # запускаем экземпляр `thread` thread.start() # Старт потока №0 # Старт потока №1 # Завершение работы потока №0 # Завершение работы потока №1
Thread.run()
:Метод Thread.run()
представляет активность потока.
Стандартный метод Thread.run()
вызывает вызываемый объект (функцию), переданный конструктору объекта в качестве целевого аргумента target
, если таковой имеется, с позиционными аргументами args
и ключевыми аргументами kwargs
.
Метод Thread.run()
можно переопределить в пользовательском подклассе. Например:
import threading, time class Worker(threading.Thread): def __init__(self, num_thread): # вызываем конструктор базового класса super().__init__() # определяем аргументы собственного класса self.num_thread = num_thread def run(self): # теперь код функции 'worker()', которая должна # выполняться в отдельных потоках будет здесь print(f'Старт потока №{self.num_thread}') time.sleep(1) print(f'Завершение работы потока №{self.num_thread}') for i in range(2): # Создаем экземпляры класса 'Worker()' th = Worker(i) # запускаем потоки th.start() # Старт потока №0 # Старт потока №1 # Завершение работы потока №0 # Завершение работы потока №1
Thread.join(timeout=None)
:Метод Thread.join()
ждет, пока поток не завершится. Этот метод блокирует вызывающий поток до тех пор, пока поток, чей метод .join()
вызывается, не завершится - либо обычно, либо через необработанное исключение, либо пока не наступит необязательный тайм-аут timeout
.
Когда присутствует аргумент timeout
не равный None
, то это должно быть число с плавающей запятой, указывающее тайм-аут для операции в секундах или его долях. Поскольку метод Thread.join()
всегда возвращает None
, то для определения жив ли поток или время ожидания вызова Thread.join()
истекло, необходимо вызвать метод Thread.is_alive()
после .join()
Когда аргумент тайм-аута отсутствует или timeout=None
, то операция будет заблокирована до завершения потока.
Поток можно присоединять много раз.
Метод Thread.join()
вызывает исключение RuntimeError
, если предпринимается попытка присоединиться к текущему потоку (самому к себе), поскольку это может вызвать взаимоблокировку. Также ошибкой является присоединения потока до того, как он был запущен методом Thread.start()
, а попытки сделать это - вызывают то же исключение.
import threading, time def worker(i): n = i + 1 print(f'Запуск потока №{n}') time.sleep(2) print(f'Поток №{n} выполнился.') for i in range(2): thread = threading.Thread(target=worker, args=(i,)) thread.start() # если присоединять 'thread.join()' потоки здесь, # то они будут запускаться по очереди, т.к. # основной поток программы будет ждать конца # выполнения присоединенного потока, прежде # чем запустить следующий print('Потоки запущены, основной поток программы так же выполняется') # получаем экземпляр основного потока main_thread = threading.main_thread() # объединим потоки, что бы дождаться их выполнения for t in threading.enumerate(): # Список 'threading.enumerate()' включает в себя основной # поток и т.к. присоединение основного потока самого к себе # вызывает взаимоблокировку, то его необходимо пропустить if t is main_thread: continue print(f'Ожидание выполнения потока {t.name}') t.join() print('Основной поток программы после ожидания продолжает работу') # Запуск потока №1 # Запуск потока №2 # Потоки запущены, основной поток программы так же выполняется # Ожидание выполнения потока Thread-1 # Поток №2 выполнился. # Поток №1 выполнился. # Ожидание выполнения потока Thread-2 # Основной поток программы после ожидания продолжает работу
Смотрите "Общий пример создания потоков", что бы узнать как проще объединять потоки.
Thread.name
:Атрибут Thread.name
это строка, используется только для идентификации потока. У нее нет какой либо семантики. Несколько потоков могут иметь одно и то же имя. Начальное имя задается в конструкторе аргументом name
.
import threading, time def worker(): # получаем экземпляр Thread и атрибутом # .name извлекаем имя потока thread_name = threading.current_thread().name print(f'Старт {thread_name}') time.sleep(1) th1 = threading.Thread(target=worker) # присвоение имени потока через атрибут th1.name = 'FirstWorker' th1.start() # присвоение имени потока в конструкторе th2 = threading.Thread(name='SecondWorker', target=worker) th2.start() # Старт FirstWorker # Старт SecondWorker
Thread.setName()
,Thread.getName()
:Методы Thread.setName()
и Thread.getName()
представляют собой старый API getter
/setter
для имени потока. Вместо этих методов используйте непосредственно атрибут Thread.name
как свойство класса.
Устарел и не рекомендуется использовать, начиная с версии Python 3.10.
Thread.ident
:Атрибут Thread.ident
идентификатор потока или None
, если поток не был запущен. Это ненулевое целое число. Подробнее смотрите функцию threading.get_ident()
.
Идентификаторы потока могут быть повторно использованы при выходе из потока и создании другого потока. Идентификатор доступен даже после выхода из потока.
Thread.native_id
:Атрибут Thread.native_id
собственный интегральный идентификатор потока. Это неотрицательное целое число или None
, если поток не был запущен. Подробнее смотрите функцию threading.get_native_id()
.
Атрибут Thread.native_id
представляет собой идентификатор потока (TID), присвоенный потоку ОС (ядром). Его значение может использоваться для однозначной идентификации этого конкретного потока в масштабах всей системы до завершения потока, после чего значение может быть переработано ОС.
Примечание. Подобно идентификаторам процессов, идентификаторы потоков действительны (гарантированно уникальны для всей системы) только с момента создания потока до момента его завершения.
Доступность: требуется функция threading.get_native_id()
.
Новое в Python 3.8.
Thread.is_alive()
:Метод Thread.is_alive()
сообщает, жив ли поток.
Этот метод возвращает True
непосредственно перед запуском метода Thread.run()
до тех пор, пока метод Thread.run()
не завершится.
Функция модуля threading.enumerate()
возвращает список всех живых потоков.
Thread.daemon
:Атрибут Thread.daemon
представляет собой логическое значение, указывающее, является ли этот поток, потоком демона (True) или нет (False).
Атрибут Thread.daemon
должен быть установлен до вызова метода Thread.start()
, в противном случае возникает исключение RuntimeError
.
Его начальное значение наследуется от создающего потока. Основной поток не является потоком демона и поэтому все потоки, созданные в основном потоке, по умолчанию имеют значение daemon = False
.
Вся программа Python завершается, когда не остается живых потоков, не являющихся демонами.
Устанавливается и извлекается так же, как атрибут Thread.name
, только имеет значение bool
.
Thread.setDaemon()
,Thread.isDaemon()
:Методы Thread.setDaemon()
и Thread.isDaemon()
представляют собой старый API для getter
/setter
для атрибута daemon
. Вместо этих методов используйте атрибут Thread.daemon
напрямую как свойство.
Устарел и не рекомендуется использовать, начиная с версии Python 3.10.
Thread
.import threading def worker(i): """thread worker function""" print(f'Worker-{i}') threads = [] # запускаем функцию 'worker()' # для выполнения в 5-ти потоках for i in range(5): t = threading.Thread(target=worker, args=(i,)) threads.append(t) t.start() # блокируем дальнейшее выполнение программы # пока не закончат выполняться все 5 потоков [thread.join() for thread in threads]