Background and Problem Description
Multi-threading allows you to run your program concurrently. You can achieve this by using threads.
π‘ Definition: In simple terms, a thread is a set of instructions that can be executed independently to perform some task. One thread might run a part of the program while the other runs another part. We can achieve multi-threading in Python using a standard Python library called threading.
Consider the following example. This program creates two threads and executes them.
import logging import threading import time def thread_function(): logging.info("thread_function : Thread in action") time.sleep(2) if __name__=="__main__" : #Set up the default handler logging.basicConfig(format="%(message)s", level=logging.INFO) # Create the threads logging.info("main : Creating the threads") t1= threading.Thread(target=thread_function) t2= threading.Thread(target=thread_function) # Run the threads logging.info("main : Calling the threads") t1.start() t2.start() logging.info("main : Completed executing threads")
Output:
main : Creating the threads main : Calling the threads thread_function : Thread in action thread_function : Thread in action main : Completed executing threads
𧩠Exercise: Do you see a problem?
Both the threads execute. But when you look at the log messages, it is hard to identify the thread instance that is running.
In complex programs, it is of utmost importance to know the instance of the thread that is running. If an error arises, these messages come in handy to understand where the problem lies.
To solve this problem, pass an argument explicitly to identify the threads. We can do it while creating an instance of a thread, as shown below.
threading.Thread(target=thread_function, args=('<name>',))
In the below code snippet, we pass t1, t2
as names for the threads.
import logging import threading import time def thread_function(name): logging.info("%s : Thread in action", name) time.sleep(2) if __name__=="__main__" : # Set up the default handler logging.basicConfig(format="%(message)s", level=logging.INFO) # Create the threads and explicitly passing a name logging.info("main : Creating the threads") t1= threading.Thread(target=thread_function, args=('t1',)) t2= threading.Thread(target=thread_function, args=('t2',)) # Run the threads logging.info("main : Calling the threads") t1.start() t2.start() logging.info("main : Completed executing threads")
As you can see, instead of thread_function
, we see the names t1, t2
in the logs.
main : Creating the threads main : Calling the threads t1 : Thread in action t2 : Thread in action main : Completed executing threads
It solves the problem to some extent.
But imagine a complex program with several threads. Passing a name to every thread is an overhead. Not just that, we have to manually check and ensure that we are passing the unique values.
So what do we do? Well, we can make use of the Thread-ID to identify a thread. Thread ID would be unique for all the active threads.
If you are wondering how to obtain the thread ID, read along. This guide covers different ways of getting a thread ID in Python.
Method 1: Using threading.get_ident() function
In Python 3.3+, you can use threading.get_ident()
function to obtain the thread ID of a thread.
threading.get_ident()
returns the thread ID of the current thread. It is a non-zero integer. The thread-specific data is stored in a dictionary format. The ID returned from thread_get_ident()
is the key value used to index this dictionary.
π‘ Resource: To find out more about this function, check this link.
Alternatively, you can also use threading.current_thread().ident
In the below code snippet, we use threading.get_ident()
to obtain the thread IDs.
import logging import threading import time def thread_function(): # Use threading.get_ident() to show the Thread ID logging.info("%d : Thread in action",threading.get_ident()) time.sleep(2) if __name__=="__main__" : # Set up the default handler logging.basicConfig(format="%(message)s ", level=logging.INFO) # Creating the threads logging.info("main : Creating the threads") t1= threading.Thread(target=thread_function) t2= threading.Thread(target=thread_function) # Run the threads logging.info("main : Calling the threads") t1.start() t2.start() logging.info("main : Completed executing threads")
As you can see, instead of the thread names (t1, t2
), a unique identifier is returned for each thread.
main : Creating the threads main : Calling the threads 6264 : Thread in action 17764 : Thread in action main : Completed executing threads
Method 2: Using threading.get_native_id() function
In Python 3.8+, you can use threading.get_native_id()
function to obtain the thread ID.
threading.get_native_id()
returns the thread ID of the current thread as assigned by the kernel of a native operating system. It is a non-zero integer. This value identifies the current thread throughout the system.
π‘ Resource: To find out more about this function, check this link.
Alternatively, you can also use threading.current_thread().native_id
In the below code snippet, we use threading.get_native_id()
to obtain the thread IDs.
import logging import threading import time def thread_function(): # Use threading.get_native_id() to show the Thread ID logging.info("%d : Thread in action",threading.get_native_id()) time.sleep(2) if __name__=="__main__" : #Set up the default handler logging.basicConfig(format="%(message)s ", level=logging.INFO) # Creating the threads logging.info("main : Creating the threads") t1= threading.Thread(target=thread_function) t2= threading.Thread(target=thread_function) # Run the threads logging.info("main : Calling the threads") t1.start() t2.start() logging.info("main : Completed executing threads")
As you can see, instead of the thread names (t1, t2
), a unique identifier is returned for each thread.
main : Creating the threads main : Calling the threads 12268 : Thread in action 8588 : Thread in action main : Completed executing threads
Method 3: Use the logging module to display its Thread ID
The logging module enables you to add the thread id in the log message. We can add the %(thread)d
mapping key in the logger format string as shown below.
logging.basicConfig(format="%(thread)d : %(message)s ", level=logging.INFO)
In the below code snippet, we use the %(thread)d
mapping key to display the Thread ID in the log messages.
import logging import threading import time def thread_function(): logging.info("Thread in action") time.sleep(2) if __name__=="__main__" : #Set up the default handler logging.basicConfig(format="%(thread)d : %(message)s ", level=logging.INFO) # Create the threads logging.info("main : Creating the threads") t1= threading.Thread(target=thread_function) t2= threading.Thread(target=thread_function) # Run the threads logging.info("main : Calling the threads") t1.start() t2.start() logging.info("main : Completed executing threads")
As you can see, a unique identifier is added to identify the threads.
6868 : main : Creating the threads 6868 : main : Calling the threads 6508 : Thread in action 1512 : Thread in action 6868 : main : Completed executing threads
Summary
In this article, we have seen three different ways of getting the thread identifiers for a thread. We hope this guide has been informative. Please subscribe to us to receive more interesting content. Thank you for Reading.
Happy Pythoning!