268

I have a multi-threading Python program, and a utility function, writeLog(message), that writes out a timestamp followed by the message. Unfortunately, the resultant log file gives no indication of which thread is generating which message.

I would like writeLog() to be able to add something to the message to identify which thread is calling it. Obviously I could just make the threads pass this information in, but that would be a lot more work. Is there some thread equivalent of os.getpid() that I could use?

ivanleoncz
  • 9,070
  • 7
  • 57
  • 49
Charles Anderson
  • 19,321
  • 13
  • 57
  • 73

8 Answers8

354

threading.get_ident() works, or threading.current_thread().ident (or threading.currentThread().ident for Python < 2.6).

Asclepius
  • 57,944
  • 17
  • 167
  • 143
Nicholas Riley
  • 43,532
  • 6
  • 101
  • 124
  • 4
    Corrected your links Nicholas. I recently realised that if you hover over a title in the docs a little red symbol appears to the right. Copy+paste that for more specific links to the docs :-) – Jon Cage May 28 '09 at 09:31
  • Thanks. I was wondering where the permalinks had got to in the new documentation format. – Nicholas Riley May 28 '09 at 09:33
  • 2
    Note that if you're using Jython, you want `threading.currentThread()` (camelCase, not camel_case) as of version 2.5. – Cam Jackson Aug 31 '11 at 02:45
  • 4
    @CharlesAnderson beware, the python docs on [Thread.name](http://docs.python.org/2/library/threading.html#threading.Thread.name) say "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." – drevicko Dec 04 '12 at 06:10
  • 7
    Also note that at least in Python 2.5 and 2.6 on OS X, there seems to be a bug where `threading.current_thread().ident` is inappropriately `None`. Probably makes sense just to use `thread.get_ident()` in Python 2 and `threading.current_thread().ident` in Python 3. – Nicholas Riley Dec 04 '12 at 09:50
  • 6
    Previous versions of my answer *did* mention `thread.get_ident()` (`threading.get_ident()` was added in Python 3.3 — follow the links to the documentation). – Nicholas Riley Jan 14 '17 at 17:00
  • @NicholasRiley - What about for Python 3.0? Or 3.0 - 3.2, I should say, before `.get_ident()` was added... – GaryMBloom Jan 28 '20 at 03:24
  • Ah, it looks like `threading.current_thread().ident` would be the way to go for Py3.0-3.2... – GaryMBloom Jan 28 '20 at 14:10
  • 1
    Is it possible to retreive native_id as well? – alper Jun 17 '20 at 17:13
  • p.s. - `threading.current_thread().ident` works for my on python2.7 on OSX – Shay Tsadok Jan 27 '21 at 09:49
  • Thank you. In case I have multiple threads running under the same thread, how do I know the ID of one of them please? – Avv Nov 01 '22 at 15:53
  • 1
    @Avv Do you mean you are in a system where multiple Python threads run under a single OS thread? I am not aware of any Python implementations where this is the case. Please see https://stackoverflow.com/questions/8623573/what-is-a-python-thread – Nicholas Riley Nov 04 '22 at 15:29
96

Using the logging module you can automatically add the current thread identifier in each log entry. Just use one of these LogRecord mapping keys in your logger format string:

%(thread)d : Thread ID (if available).

%(threadName)s : Thread name (if available).

and set up your default handler with it:

logging.basicConfig(format="%(threadName)s:%(message)s")
Community
  • 1
  • 1
kraymer
  • 3,254
  • 1
  • 24
  • 32
  • 1
    I am using logger. So I think you answer is the simplest solution. But I am getting `_2` this as a thread name. Is that two is my thread number which invoked – Ravi Shanker Reddy May 30 '17 at 05:06
  • the PID seems to be needed in some cases to make it somewhat unique, at least (pyspark). So combining PID and thread-id seems to do the job: "%(thread)d-%(process)d" – selle Sep 29 '22 at 10:53
  • Thank you. In case I have multiple threads running under the same thread, how do I know the ID of one of them please? – Avv Nov 01 '22 at 15:53
40

This functionality is now supported by Python 3.8+ :)

You can now use: threading.get_native_id()

https://github.com/python/cpython/commit/4959c33d2555b89b494c678d99be81a65ee864b0

https://github.com/python/cpython/pull/11993

Quinten C
  • 660
  • 1
  • 8
  • 18
Jake Tesler
  • 484
  • 5
  • 5
  • 3
    It is important to note that `.get_ident()` is a number assigned by the Python interpreter and `.get_native_id()` is the actual Thread ID that the kernel assigns to the thread when this is created. – Pavel Razgovorov Dec 07 '22 at 12:02
  • This worked perfectly as an alternative to brucexin's answer, which didn't work on some older machines – MANA624 Jan 23 '23 at 19:56
  • Note: If you spawn a secondary thread in a C++ extension, and callback into a Python function from there, they will report the same system thread id with this method, making that threading easy to follow across those layers! – BuvinJ Jul 19 '23 at 22:52
32

The thread.get_ident() function returns a long integer on Linux. It's not really a thread id.

I use this method to really get the thread id on 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)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
brucexin
  • 435
  • 4
  • 5
  • This can be used sometimes but is not portable – Piyush Kansal Feb 25 '12 at 20:51
  • 3
    Could you please edit this answer so it will continue to be useful to visitors if the link becomes bad? – josliber Jun 29 '16 at 12:51
  • how to wrap the start() method of my thread class so it can fill my self.pid with it's pid everytime I launch the thread? Tried os.kill(pid) from inside the own thread, it just stops all the threads including the main, must be done externally by the parent, but how to get that child pid from the parent? – Rodrigo Formighieri Feb 27 '19 at 12:41
  • As others have hinted, this sadly does not work on something like an embedded linux running on a 32 bit Arm. – Travis Griggs Sep 23 '19 at 23:48
  • 1
    @TravisGriggs The concept is portable to Linux, including 32 bit ARM platforms. You just need to get the correct system call number, which is probably going to be 224 on ARM and ARM64. It could be determined at build or run time with a small C program. This works for me with Python 3.7 on an RPi. Jake Tesler's answer is better if you have Python 3.8, which is not present in Raspbian 10 yet. – TrentP Dec 03 '19 at 22:19
  • @TravisGriggs You can also do something like "grep -ri SYS_gettid /usr/include/" to find the ID of your sys call. – Javon Jan 06 '21 at 20:54
21

You can get the ident of the current running thread. The ident could be reused for other threads, if the current thread ends.

When you crate an instance of Thread, a name is given implicit to the thread, which is the pattern: Thread-number

The name has no meaning and the name don't have to be unique. The ident of all running threads is unique.

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

The function threading.current_thread() returns the current running thread. This object holds the whole information of the thread.

DeaD_EyE
  • 433
  • 5
  • 10
  • Thank you. In case I have multiple threads running under the same thread, how do I know the ID of one of them please? – Avv Nov 01 '22 at 15:53
7

I saw examples of thread IDs like this:

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

The threading module docs lists name attribute as well:

...

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
  • 181,842
  • 47
  • 306
  • 310
  • Thank you. In case I have multiple threads running under the same thread, how do I know the ID of one of them please? – Avv Nov 01 '22 at 15:53
0

I created multiple threads in Python, I printed the thread objects, and I printed the id using the ident variable. I see all the ids are same:

<Thread(Thread-1, stopped 140500807628544)>
<Thread(Thread-2, started 140500807628544)>
<Thread(Thread-3, started 140500807628544)>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 6
    I guess it is recycled, as the docs for `ident` say: `Thread identifiers may be recycled when a thread exits and another thread is created.` https://docs.python.org/2/library/threading.html#threading.Thread.ident – oblalex Dec 13 '15 at 17:23
0

Similarly to @brucexin I needed to get OS-level thread identifier (which != thread.get_ident()) and use something like below not to depend on particular numbers and being amd64-only:

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

and

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

...

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

this depends on Cython though.

kirr
  • 391
  • 4
  • 8
  • I was hopeful this would be cross platform version I was looking for, but I get an error on this, `invalid syntax` pointer after `extern` keyword. Is there something I'm missing. Is it important that the code be in a separate module and have the pyx extension? Or is this a (re)compile thing? – Travis Griggs Sep 24 '19 at 00:05
  • Yes, this depends on Cython and should reside in a `.pyx` file. For "pure python" probably something similar could be done with ctypes too. – kirr Sep 24 '19 at 09:21