Jak znaleźć identyfikator wątku w Pythonie

179

Mam wielowątkowy program w Pythonie i funkcję narzędziową writeLog(message), która zapisuje znacznik czasu, po którym następuje komunikat. Niestety, wynikowy plik dziennika nie wskazuje, który wątek generuje dany komunikat.

Chciałbym writeLog()móc dodać coś do wiadomości, aby określić, który wątek ją wywołuje. Oczywiście mógłbym po prostu zmusić wątki do przekazywania tych informacji, ale wymagałoby to znacznie więcej pracy. Czy jest jakiś odpowiednik wątku os.getpid(), którego mógłbym użyć?

Charles Anderson
źródło

Odpowiedzi:

227

threading.get_ident()działa lub threading.current_thread().ident(lub threading.currentThread().identdla Pythona <2.6).

Nicholas Riley
źródło
3
Poprawione linki Nicholas. Niedawno zdałem sobie sprawę, że jeśli najedziesz kursorem na tytuł w dokumentach, po prawej stronie pojawi się mały czerwony symbol. Skopiuj i wklej to, aby uzyskać bardziej szczegółowe linki do dokumentów :-)
Jon Cage
2
Zauważ, że jeśli używasz Jythona, chcesz threading.currentThread()(camelCase, a nie camel_case) od wersji 2.5.
Cam Jackson
3
@CharlesAnderson, uwaga, dokumentacja Pythona na Thread.name mówi: „name - Ciąg używany tylko do celów identyfikacyjnych. Nie ma semantyki. Wiele wątków może mieć tę samą nazwę. Początkowa nazwa jest ustawiana przez konstruktor”.
drevicko
7
Zauważ również, że przynajmniej w Pythonie 2.5 i 2.6 na OS X wydaje się, że jest błąd, który threading.current_thread().identjest nieprawidłowy None. Prawdopodobnie ma sens po prostu użycie thread.get_ident()w Pythonie 2 i threading.current_thread().identPythonie 3.
Nicholas Riley
5
Poprzednie wersje moją odpowiedź nie wspomina thread.get_ident()( threading.get_ident()dodano w Pythonie 3.3 - wykonaj linki do dokumentacji).
Nicholas Riley
68

Korzystając z modułu rejestrowania , możesz automatycznie dodać bieżący identyfikator wątku do każdego wpisu dziennika. Po prostu użyj jednego z tych kluczy mapowania LogRecord w ciągu formatu loggera:

% (wątek) d: identyfikator wątku (jeśli jest dostępny).

% (threadName) s: nazwa wątku (jeśli jest dostępna).

i skonfiguruj z nim domyślną procedurę obsługi:

logging.basicConfig(format="%(threadName)s:%(message)s")
kraymer
źródło
Używam loggera. Więc myślę, że twoja odpowiedź jest najprostszym rozwiązaniem. Ale otrzymuję <concurrent.futures.thread.ThreadPoolExecutor object at 0x7f00f882a438>_2 to jako nazwę wątku. Czy to dwa to numer mojego wątku, który wywołał
Ravi Shanker Reddy
22

thread.get_ident()Zwraca długą liczbę całkowitą w systemie Linux. To naprawdę nie jest identyfikator wątku.

Używam tej metody, aby naprawdę uzyskać identyfikator wątku w systemie 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
źródło
Może być używany czasami, ale nie jest przenośny
Piyush Kansal
3
Czy możesz zmienić tę odpowiedź, aby nadal była przydatna dla odwiedzających, jeśli link stanie się zły?
josliber
jak opakować metodę start () mojej klasy wątku, aby mogła wypełnić mój self.pid swoim pid za każdym razem, gdy uruchamiam wątek? Wypróbowany os.kill (pid) z wnętrza własnego wątku, po prostu zatrzymuje wszystkie wątki, w tym główny, musi być wykonane zewnętrznie przez rodzica, ale jak uzyskać ten pid dziecka od rodzica?
Rodrigo Formighieri
Jak wspominali inni, niestety nie działa to na czymś w rodzaju osadzonego linuxa działającego na 32-bitowym Arm.
Travis Griggs
@TravisGriggs Koncepcja jest przenośna do Linuksa, w tym 32-bitowych platform ARM. Musisz tylko uzyskać poprawny numer wywołania systemowego, który prawdopodobnie będzie równy 224 na ARM i ARM64. Można to określić podczas kompilacji lub uruchamiania za pomocą małego programu w C. To działa dla mnie z Pythonem 3.7 na RPi. Odpowiedź Jake'a Teslera jest lepsza, jeśli masz Pythona 3.8, którego jeszcze nie ma w Raspbian 10.
TrentP
7

Widziałem przykłady takich identyfikatorów wątków:

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

W docs modułu gwintowania listy nameatrybutów, a także:

...

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.
miku
źródło
7

Możesz uzyskać identyfikator aktualnie działającego wątku. Identyfikator może zostać ponownie użyty dla innych wątków, jeśli bieżący wątek się zakończy.

Kiedy tworzysz wystąpienie Thread, wątkowi jest nadawana niejawna nazwa, która jest wzorcem: Numer-wątku

Nazwa nie ma znaczenia i nie musi być unikalna. Identyfikator wszystkich uruchomionych wątków jest unikalny.

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()

Funkcja threading.current_thread () zwraca bieżący wątek. Ten obiekt zawiera wszystkie informacje o wątku.

DeaD_EyE
źródło
0

Utworzyłem wiele wątków w Pythonie, wydrukowałem obiekty wątków i wydrukowałem id za pomocą identzmiennej. Widzę, że wszystkie identyfikatory są takie same:

<Thread(Thread-1, stopped 140500807628544)>
<Thread(Thread-2, started 140500807628544)>
<Thread(Thread-3, started 140500807628544)>
shoaib shaikh
źródło
4
Wydaje mi się, że został poddany recyklingowi, jak identmówią dokumenty : 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

Podobnie jak w przypadku @brucexin, potrzebowałem uzyskać identyfikator wątku na poziomie systemu operacyjnego (który! = thread.get_ident()) I użyć czegoś takiego jak poniżej, aby nie polegać na konkretnych liczbach i być tylko 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)                                                                  

i

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

...

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

zależy to jednak od Cythona.

kirr
źródło
Miałem nadzieję, że będzie to wersja wieloplatformowa, której szukałem, ale pojawia się błąd, invalid syntaxwskaźnik po externsłowie kluczowym. Czy jest coś, czego mi brakuje. Czy ważne jest, aby kod znajdował się w osobnym module i miał rozszerzenie pyx? A może jest to (ponowna) kompilacja?
Travis Griggs
Tak, zależy to od Cythona i powinno znajdować się w .pyxpliku. Dla „czystego Pythona” prawdopodobnie coś podobnego można by zrobić z ctypami.
kirr