Як знайти ідентифікатор потоку в 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.
Cam Jackson

3
@CharlesAnderson, будьте обережні, документи python на ім'я Thread.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.
Nicholas Riley

5
Попередні версії моєї відповіді зробили згадка thread.get_ident()( threading.get_ident()був доданий в Python 3.3 - слідувати посиланнях на документацію).
Ніколас Райлі

68

Використовуючи модуль журналу, ви можете автоматично додавати поточний ідентифікатор потоку у кожну запис журналу. Просто використовуйте один із цих ключів відображення LogRecord у рядку формату реєстратора:

% (нитка) d: ідентифікатор нитки (якщо є).

% (threadName) s: ім'я теми (якщо є).

і налаштувати з ним обробник за замовчуванням:

logging.basicConfig(format="%(threadName)s:%(message)s")

Я використовую реєстратор. Тож я думаю, що ви відповідаєте - це найпростіше рішення. Але я отримую <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)

Це можна використовувати іноді, але не є портативним
Піюш Кансал

3
Чи можете ви відредагувати цю відповідь, щоб вона залишалася корисною для відвідувачів, якщо посилання стане поганим?
josliber

як обернути метод start () мого класу потоків, щоб він міг заповнювати свій self.pid своїм pid кожного разу, коли я запускаю нитку? Спробував os.kill (pid) зсередини власної нитки, він просто зупиняє всі потоки, включаючи основну, повинен виконуватись батьком зовні, але як отримати цей дочірний під від батьків?
Родріго Форміг’єрі

Як натякнули інші, це, на жаль, не працює на щось подібне до вбудованого Linux, який працює на 32-бітній руці.
Тревіс Гріггс

@TravisGriggs Концепція є портативною для Linux, включаючи 32-бітні платформи ARM. Вам просто потрібно отримати правильний номер виклику системи, який, ймовірно, буде 224 для ARM та ARM64. Це можна визначити під час збирання або запуску за допомогою невеликої програми C. Це працює для мене з Python 3.7 на RPi. Відповідь Джейка Теслера краще, якщо у вас є Python 3.8, якого ще немає в програмі Raspbian 10.
TrentP


7

Я бачив приклади ідентифікаторів потоку на зразок цього:

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

Документи для нарізування модулів також вказують 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, ім’я дається неявно для потоку, що є шаблоном: Thread-number

Ім'я не має значення, і ім'я не повинно бути унікальним. Ідентифікація всіх запущених потоків унікальна.

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 () повертає поточний запущений потік. Цей об’єкт вміщує всю інформацію потоку.


0

Я створив декілька потоків у Python, надрукував об’єкти потоку та надрукував ідентифікатор за допомогою identзмінної. Я бачу, що всі ідентичні файли однакові:

<Thread(Thread-1, stopped 140500807628544)>
<Thread(Thread-2, started 140500807628544)>
<Thread(Thread-3, started 140500807628544)>

4
Я думаю, він переробляється, як 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.


Я сподівався, що це буде кросова платформа, яку я шукав, але я отримую помилку щодо цього, invalid syntaxвказівник за externключовим словом. Щось мені не вистачає. Чи важливо, щоб код знаходився в окремому модулі і мав розширення pyx? Або це (пере) компіляція?
Тревіс Гріггс

Так, це залежить від Cython і має знаходитись у .pyxфайлі. Для "чистого пітона", мабуть, щось подібне можна було б зробити і з ctypes.
kirr
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.