Como encontrar um ID de thread em Python

178

Eu tenho um programa Python com vários threads e uma função de utilitário writeLog(message), que grava um carimbo de data e hora seguido pela mensagem. Infelizmente, o arquivo de log resultante não fornece indicação de qual thread está gerando qual mensagem.

Gostaria writeLog()de poder adicionar algo à mensagem para identificar qual thread está chamando. Obviamente, eu poderia fazer com que os threads passassem essas informações, mas isso seria muito mais trabalhoso. Existe algum segmento equivalente ao os.getpid()que eu poderia usar?

Charles Anderson
fonte

Respostas:

226

threading.get_ident()funciona, ou threading.current_thread().ident(ou threading.currentThread().identpara Python <2.6).

Nicholas Riley
fonte
3
Corrigido seus links Nicholas. Recentemente, percebi que, se você passar o mouse sobre um título nos documentos, um pequeno símbolo vermelho aparecerá à direita. Cópia + a pasta que para mais links específicos para os docs :-)
Jon gaiola
2
Observe que se você estiver usando Jython, deseja threading.currentThread()(camelCase, não camel_case) a partir da versão 2.5.
Cam Jackson
3
@CharlesAnderson, cuidado, os documentos python no Thread.name dizem "name - Uma string usada apenas para fins de identificação. Não possui semântica. Vários threads podem receber o mesmo nome. O nome inicial é definido pelo construtor."
Drevicko
7
Observe também que, pelo menos no Python 2.5 e 2.6 no OS X, parece haver um erro que threading.current_thread().identé inapropriado None. Provavelmente faz sentido apenas usar thread.get_ident()no Python 2 e threading.current_thread().identno Python 3. #
Nicholas Riley
5
As versões anteriores do minha resposta fez menção thread.get_ident()( threading.get_ident()foi adicionada no Python 3.3 - siga os links para a documentação).
Nicholas Riley
67

Usando o módulo de log , você pode adicionar automaticamente o identificador de segmento atual em cada entrada de log. Basta usar uma dessas chaves de mapeamento do LogRecord na sua sequência de formato de logger:

% (segmento) d: ID do segmento (se disponível).

% (threadName) s: nome do segmento (se disponível).

e configure seu manipulador padrão com ele:

logging.basicConfig(format="%(threadName)s:%(message)s")
kraymer
fonte
Estou usando o logger. Então eu acho que você responde é a solução mais simples. Mas estou recebendo <concurrent.futures.thread.ThreadPoolExecutor object at 0x7f00f882a438>_2 isso como um nome de thread. É que dois é o meu número de discussão que invocado
Ravi Shankar Reddy
22

A thread.get_ident()função retorna um número inteiro longo no Linux. Não é realmente um ID de thread.

Eu uso esse método para realmente obter a identificação do segmento no 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)
brucexina
fonte
Isso pode ser usado algumas vezes, mas não é portátil
Piyush Kansal
3
Você poderia editar esta resposta para continuar a ser útil para os visitantes se o link ficar ruim?
josliber
como quebrar o método start () da minha classe de thread para que ele possa preencher meu self.pid com o pid toda vez que inicio o thread? Tentou o os.kill (pid) de dentro do próprio encadeamento, ele apenas interrompe todos os encadeamentos, incluindo o principal, devem ser executados externamente pelo pai, mas como obter esse filho filho do pai?
Rodrigo Formighieri
Como outros sugeriram, isso infelizmente não funciona em algo como um linux incorporado rodando em um Arm de 32 bits.
Travis Griggs
@TravisGriggs O conceito é portátil para Linux, incluindo plataformas ARM de 32 bits. Você só precisa obter o número de chamada do sistema correto, que provavelmente será 224 no ARM e ARM64. Pode ser determinado no tempo de compilação ou execução com um pequeno programa C. Isso funciona para mim com o Python 3.7 em um RPi. A resposta de Jake Tesler é melhor se você tiver o Python 3.8, que ainda não está presente no Raspbian 10.
precisa saber é o seguinte
7

Eu vi exemplos de IDs de threads como este:

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

Os documentos do módulo de encadeamento listam também o nameatributo:

...

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
fonte
7

Você pode obter o ident do segmento em execução atual. O ident pode ser reutilizado para outros encadeamentos, se o encadeamento atual terminar.

Quando você cria uma instância do Thread, é atribuído um nome implícito ao thread, que é o padrão: Thread-number

O nome não tem significado e o nome não precisa ser exclusivo. O ident de todos os threads em execução é exclusivo.

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

A função threading.current_thread () retorna o thread em execução atual. Este objeto contém todas as informações do encadeamento.

DeaD_EyE
fonte
0

Criei vários threads em Python, imprimi os objetos de thread e imprimi o ID usando a identvariável Vejo que todos os IDs são iguais:

<Thread(Thread-1, stopped 140500807628544)>
<Thread(Thread-2, started 140500807628544)>
<Thread(Thread-3, started 140500807628544)>
shoaib shaikh
fonte
4
Eu acho que é reciclado, como a documentação para identdizer: 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

Da mesma forma que o @brucexin, eu precisava obter o identificador de segmento no nível do SO (que! = thread.get_ident()) E usar algo como abaixo para não depender de números específicos e ser apenas para 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)                                                                  

e

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

...

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

isso depende do Cython.

kirr
fonte
Eu esperava que essa fosse a versão de plataforma cruzada que eu estava procurando, mas eu recebo um erro sobre isso, invalid syntaxponteiro após externpalavra-chave. Tem algo que estou perdendo. É importante que o código esteja em um módulo separado e tenha a extensão pyx? Ou isso é uma coisa de (re) compilação?
Travis Griggs
Sim, isso depende do Cython e deve residir em um .pyxarquivo. Para "python puro", provavelmente algo semelhante também poderia ser feito com ctypes.
Kirr