Как найти идентификатор потока в Python

179

У меня есть многопоточная программа Python и служебная функция writeLog(message), которая записывает метку времени, за которой следует сообщение. К сожалению, полученный файл журнала не указывает, какой поток генерирует какое сообщение.

Я хотел бы writeLog()иметь возможность добавить что-то к сообщению, чтобы определить, какой поток вызывает его. Очевидно, я мог бы просто заставить потоки передавать эту информацию, но это было бы намного больше работы. Есть ли какой-нибудь поток-эквивалент, os.getpid()который я мог бы использовать?

Чарльз Андерсон
источник

Ответы:

227

threading.get_ident()работает, или threading.current_thread().ident(или threading.currentThread().identдля Python <2.6).

Николас Райли
источник
3
Исправил твои ссылки Николай. Недавно я понял, что если вы наведете курсор на заголовок документа, справа появится красный символ. Скопируйте и вставьте это для более конкретных ссылок на документы :-)
Джон Кейдж,
2
Обратите внимание, что если вы используете Jython, вы хотите threading.currentThread()(camelCase, а не camel_case) начиная с версии 2.5.
Кэм Джексон
3
@CharlesAnderson, будьте осторожны, документы Python для Thread.name говорят: «name - строка, используемая только в целях идентификации. Она не имеет семантики. Многим потокам может быть присвоено одно и то же имя. Начальное имя задается конструктором».
drevicko
7
Также обратите внимание, что по крайней мере в Python 2.5 и 2.6 на OS X, кажется, есть ошибка, threading.current_thread().identкоторая неуместна None. Вероятно, имеет смысл просто использовать thread.get_ident()в Python 2 и threading.current_thread().identв Python 3.
Николас Райли
5
Предыдущие версии моего ответа сделали упоминание thread.get_ident()( threading.get_ident()был добавлен в Python 3.3 - следовать ссылкам на документацию).
Николас Райли
68

Используя модуль регистрации, вы можете автоматически добавлять текущий идентификатор потока в каждую запись журнала. Просто используйте один из этих ключей сопоставления LogRecord в строке формата вашего регистратора:

% (поток) d: идентификатор потока (если имеется).

% (threadName) s: имя потока (если доступно).

и установите ваш обработчик по умолчанию с ним:

logging.basicConfig(format="%(threadName)s:%(message)s")
kraymer
источник
Я использую регистратор. Поэтому я думаю, что вы ответите самое простое решение. Но я получаю <concurrent.futures.thread.ThreadPoolExecutor object at 0x7f00f882a438>_2 это как имя потока. Это два, это мой номер
Рави Шенкер Редди
22

thread.get_ident()Функция возвращает длинное целое на Linux. Это на самом деле не идентификатор потока.

Я использую этот метод, чтобы действительно получить идентификатор потока в Linux:

import ctypes
libc = ctypes.cdll.LoadLibrary('libc.so.6')

# System dependent, see e.g. /usr/include/x86_64-linux-gnu/asm/unistd_64.h
SYS_gettid = 186

def getThreadId():
   """Returns OS thread id - Specific to Linux"""
   return libc.syscall(SYS_gettid)
brucexin
источник
Это может иногда использоваться, но не переносимо
Piyush Kansal
3
Не могли бы вы отредактировать этот ответ, чтобы он продолжал быть полезным для посетителей, если ссылка станет плохой?
josliber
как обернуть метод start () моего класса потока, чтобы он мог заполнять мой self.pid своим pid при каждом запуске потока? Пробовал os.kill (pid) изнутри собственного потока, он просто останавливает все потоки, включая основной, должен быть сделан родителем извне, но как получить этот дочерний pid от родителя?
Родриго Формигьери
Как уже намекали другие, это, к сожалению, не работает на чем-то похожем на встроенный Linux, работающий на 32-битной версии Arm.
Трэвис Григгс
@TravisGriggs Концепция переносима на Linux, включая 32-битные платформы ARM. Вам просто нужно получить правильный номер системного вызова, который, вероятно, будет 224 на ARM и ARM64. Это можно определить во время сборки или запуска с помощью небольшой программы на Си. Это работает для меня с Python 3.7 на RPi. Ответ Джейка Теслера будет лучше, если у вас есть Python 3.8, которого пока нет в Raspbian 10.
TrentP
7

Я видел примеры идентификаторов потоков, как это:

class myThread(threading.Thread):
    def __init__(self, threadID, name, counter):
        self.threadID = threadID
        ...

В модуле потоковой Docs списков nameатрибуты , а также:

...

A thread has a name. 
The name can be passed to the constructor, 
and read or changed through the name attribute.

...

Thread.name

A string used for identification purposes only. 
It has no semantics. Multiple threads may
be given the same name. The initial name is set by the constructor.
Мик
источник
7

Вы можете получить идентификатор текущего запущенного потока. Идентификатор может быть повторно использован для других потоков, если текущий поток заканчивается.

Когда вы создаете экземпляр Thread, для потока дается неявное имя, которое является шаблоном: номер потока

Имя не имеет значения, и имя не обязательно должно быть уникальным. Идентификатор всех запущенных потоков уникален.

import threading


def worker():
    print(threading.current_thread().name)
    print(threading.get_ident())


threading.Thread(target=worker).start()
threading.Thread(target=worker, name='foo').start()

Функция threading.current_thread () возвращает текущий запущенный поток. Этот объект содержит всю информацию о потоке.

DeaD_EyE
источник
0

Я создал несколько потоков в Python, я напечатал объекты потоков, и я напечатал идентификатор, используя identпеременную. Я вижу, все идентификаторы одинаковы:

<Thread(Thread-1, stopped 140500807628544)>
<Thread(Thread-2, started 140500807628544)>
<Thread(Thread-3, started 140500807628544)>
Шоаиб Шейх
источник
5
Я предполагаю, что это переработано, как identговорят документы : Thread identifiers may be recycled when a thread exits and another thread is created. docs.python.org/2/library/threading.html#threading.Thread.ident
oblalex
0

Как и @brucexin, мне нужно было получить идентификатор потока на уровне ОС (который! = thread.get_ident()) И использовать что-то вроде ниже, чтобы не зависеть от конкретных чисел и быть только для amd64:

---- 8< ---- (xos.pyx)
"""module xos complements standard module os""" 

cdef extern from "<sys/syscall.h>":                                                             
    long syscall(long number, ...)                                                              
    const int SYS_gettid                                                                        

# gettid returns current OS thread identifier.                                                  
def gettid():                                                                                   
    return syscall(SYS_gettid)                                                                  

и

---- 8< ---- (test.py)
import pyximport; pyximport.install()
import xos

...

print 'my tid: %d' % xos.gettid()

это зависит от Cython, хотя.

Kirr
источник
Я надеялся, что это будет кроссплатформенная версия, которую я искал, но я получаю сообщение об ошибке, invalid syntaxуказатель за externключевым словом. Есть что-то, что я пропускаю. Важно ли, чтобы код был в отдельном модуле и имел расширение pyx? Или это (пере) компиляция?
Трэвис Григгс
Да, это зависит от Cython и должно находиться в .pyxфайле. Для «чистого питона», вероятно, нечто подобное можно сделать и с ctypes.
Кирр