

Dheeraj Jha
Jun 29, 20205 min read


Dheeraj Jha
May 3, 20204 min read


Dheeraj Jha
Apr 25, 20204 min read


Dheeraj Jha
Mar 13, 20202 min read


Dheeraj Jha
Mar 4, 20203 min read

Updated: Jun 8, 2020
Threads help speed up your application. You can run your code parallelly and threads can help you to simplify your design. If you want to perform an independent task it is better to create a thread. Creating a thread will allow your main thread/process to execute.
Before creating a thread, let’s refresh some key features of thread.
Thread is called “light weight process”.
A thread is a separate flow of execution.
In a process, there may be one or more threads running simultaneously.
Each thread performs a specific task.
It takes less time for creation and context switching than process.
Threads share memory address space. Threads of a process share its virtual address space and system resources.
Each thread maintains exception handlers, a scheduling priority, thread-local storage, a unique thread identifier, and a set of structures the system will use to save the thread context until it is scheduled.
Multithreading can help speed up tasks that are IO-bound.
I/O may be from a network, database, file etc.
These I/O usually takes a significant amount of time to perform.
Threading can add more clarity in design.
Python offers 2 modules for thread creation.
_thread – It provides a low-level threading API.
threading(threading.py) - This module constructs higher-level threading interfaces on top of the lower level _thread module.
This blog will explain thread creation using the “threading” module as it gives lots of helpful APIs which you will not get in low level “_thread” module.
There are 3 ways we can create a thread in python.
Without any class
By extending Threading class
Using class without extending a thread class.
class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)threading module provides a Thread class. Thread class constructor takes keyword arguments and you should always call the constructor with keyword parameters.
group – None. Reserved for future use
target – pass a callable function/class function/callable object to be invoked by run() method.
Name – name of the thread. If no name is passed, the default name of the thread is “Thread-n” where n is a decimal number.
Args – arguments to the thread. This parameter is a tuple.
kwargs - is a dictionary of keyword arguments for the target invocation.
Daemon - sets whether the thread is daemonic. If None, the daemonic property is inherited from the current thread.
Daemon threads are stopped at shutdown. Resources acquired by this thread may not be released properly.
import threading
count1 = 0
def even(thread_name):
global count1
while count1 < 10:
if count1 % 2 == 0:
print (thread_name + ": \t", count1)
count1 = count1 + 1
thread1 = threading.Thread(target=even, args=("Even",), name="test1")
thread1.start()
thread1.join()
print("Done.")Output:

you will have to import the “threading” module to create a thread. "even()” function will print all the even numbers between 0 to 10.
After creating a thread object, you need to call start() function. This invokes run() method of Thread class.
Once thread started to run, you need to attach this thread to the main thread by calling join() method of Thread class. It joins thread1 thread to main thread and main thread waits for thread1 to complete. If you forget to join two threads, the main thread will continue to execute and exit on completion. In this case, thread1 will be left as an orphan.
import threading
count = 0
class MyThread():
def even(self, thread_name):
global count
while count < 10:
if count % 2 == 0:
print(thread_name + ": \t", count)
count = count + 1
obj = MyThread()
thread = threading.Thread(target=obj.even, args=("Even",), name="EvenThread")
thread.start()
thread.join()
print("Done.")Output:

This is another way of creating a thread using a class member method. A thread will run the target function.
import threading
count = 0
class MyThread(threading.Thread):
def __init__(self,thread_name):
super(MyThread, self).__init__(args=(thread_name,), name=thread_name)
self.thread_name = thread_name
def run(self):
global count
while count < 10:
if count % 2 == 0:
print(self.thread_name + ": \t", count)
count = count + 1
thread = MyThread("Even")
thread.start()
thread.join()
print("Done.")Output:

You can extend threading.Thread class in your sub-class. When you are extending Thread class, remember to implement a run() function which will be called internally when you will call start() method.
Python threading module offers a useful class – threading.local.
import threading
count = 0
def foo(thread_name, num):
global count
local_data = threading.local()
local_data.local_name = thread_name
local_data.x = 2 * num
while count < 50:
if count % 2 == 0:
print(local_data.x,"- \t" + local_data.local_name + ": \t", count)
count = count + 1
thread1 = threading.Thread(target=foo, args=("Thread1",2))
thread2 = threading.Thread(target=foo, args=("Thread2",3))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print("Done.")Output:

Thread local data is the data whose values are specific to threads. To have thread-local data, create an instance of threading.local class. Instance if this class can have any number of thread-local variables.
In the above example, there are two thread-local variables - local_data.local_name and local_data.x
Note: thread1 and thread2 are not synchronized. So output may vary in each run.
Name - A string used for identification purposes only.
getName() / setName() - getter/setter API for name
ident - The ‘thread identifier’ of this thread or None
native_id - The native integral thread ID of this thread.
is_alive() - Return whether the thread is alive.
Daemon - A boolean value indicating whether this thread is a daemon thread (True) or not (False).
threading.active_count() - Return the number of Thread objects currently alive.
threading.current_thread() - Return the current Thread object, corresponding to the caller’s thread of control.
threading.get_ident() - Return the ‘thread identifier’ of the current thread.
threading.get_native_id() - Return the native integral Thread ID of the current thread assigned by the kernel.
threading.enumerate() - Return a list of all Thread objects currently alive.
Having multiple threads in a python application may not speed up. Due to Global Interpreter Lock (GIL), only one thread can execute. It means, irrespective of having a multi-core machine, only one thread will execute at a time.
If you want to better use your multicores, use the multiprocessing module. I will discuss this module in another blog.
Global Interpreter Lock: From python documentation
The mechanism used by the CPython interpreter to assure that only one thread executes Python bytecode at a time. This simplifies the CPython implementation by making the object model (including critical built-in types such as dict) implicitly safe against concurrent access. Locking the entire interpreter makes it easier for the interpreter to be multi-threaded, at the expense of much of the parallelism afforded by multi-processor machines.
I hope now you have a pretty good understanding of python thread and the ways to create threads. Thread creation is a quite simpler task than thread synchronization. Most of the newcomers struggle in thread synchronization. It seems tough in the beginning but once you understand the core concept of synchronization, it will become easy. I will discuss thread synchronization methods in my next blog.










Comments