All Courses

Multithreaded Programming in Python

Neha Kumawat

3 years ago

Multithreaded Programming in Python | insideAIML
Table of Contents
  • Introduction
  • What is thread?
  • How to Start a New Thread
  • The new Module: Threading 
  • How to create thread Using Threading Module?
  • How to Synchronize the Threads?
  • How to set Multithreaded Priority Queue?

Introduction

          Python is a very interesting programming language. It provides us the facilities of multithreaded programming. Running several threads is similar to running several different programs concurrently and it providesthe following benefits to the user−
Multiple threads within a process share the same data space with the main thread and can therefore share information or communicate with each other more easily than if they were separate processes.
Threads sometimes called light-weight processes and they do not require much memory overhead; they are cheaper than process 

What is thread?

            A thread is a separate flow of execution which means that your program will have two things happening at same time. It consists of a beginning, an execution sequence, and a conclusion. It has an instruction pointer that keeps track of where within its context it is currently running.
It can be interrupted in the middle of execution or pre-empted.
It can temporarily be put on hold this is also known as sleepingwhile other threads are running which is called yielding.

How to Start a New Thread

           Python provides a thread module which is to start a thread. To spawn another thread, we need to call the below mention method which is available in python thread module.
thread.start_new_thread ( function, args[, kwargs] )
This method is used to enabled a fast and efficient way to create new threads in both Linux and Windows operating system.
It returns immediately and the child thread starts and calls function with the passed list of args. When the function returns, the thread get terminated.
Here, args is a tuple of arguments which is usedas an empty tuple to call the function without passing any arguments. kwargs is an optional dictionary of keyword arguments.
Let’s see an example
import _thread as th
import time

#Defining a function for the thread
def print_time( threadName, delay):
  count = 0
  while count < 5:
    time.sleep(delay)
    count += 1
    print ("%s: %s" % (threadName, time.ctime(time.time()) ))

#Creating two threads as follows

try:
  th.start_new_thread(
  print_time, ("Thread-1", 2, ) )

  th.start_new_thread(
  print_time, ("Thread-2", 4, ) )

except:
  print("Error occured : unable to start thread, please try again")

while True:
  pass
When I run the above code, we will get the following output. Note: If you run this code maybe you will get the output.
Thread-1: Sat Jan  1 11:35:31 2022
Thread-2: Sat Jan  1 11:35:33 2022
Thread-1: Sat Jan  1 11:35:33 2022
Thread-1: Sat Jan  1 11:35:35 2022
Thread-2: Sat Jan  1 11:35:37 2022
Thread-1: Sat Jan  1 11:35:37 2022
Thread-1: Sat Jan  1 11:35:39 2022
Thread-2: Sat Jan  1 11:35:41 2022
Thread-2: Sat Jan  1 11:35:45 2022
Thread-2: Sat Jan  1 11:35:49 2022
Mainly thread module is very effective for low-level threading, but the thread module is very limited compared to the newer threading module for new and higher version of python.

The new Module: Threading 

          Python does not support thread module in its old version. So, it provides the newer threading module included with Python 2.4 which is much more powerful, high-level support for threads than the thread module.
The new threading module exposes all the methods of the thread module and provides some additional methods such as −
·        threading.activeCount() –It returns the number of thread objects that are active.
·        threading.currentThread() –it returns the number of thread objects in the caller's thread control.
·        threading.enumerate() –it returns a list of all thread objects that are currently active.
In addition to the methods, the threading module has the Thread class that implements threading. The methods provided by the Thread class are as follows −
·        run() − The run() method is the entry point for a thread.
·        start() − The start() method starts a thread by calling the run method.
·        join([time]) − The join() waits for threads to terminate.
·        isAlive() − The isAlive() method checks whether a thread is still executing.
·        getName() − The getName() method returns the name of a thread.
·        setName() − The setName() method sets the name of a thread.

How to create thread Using Threading Module?

          If you want to create a new thread using the threading module, you have to follow the below mentioned steps −
  • First, you have defined a new subclass of the Thread class.
  • Then you have overridden the __init__ (self [, args]) method to add additional arguments.
  • Later, override the run (self [,args]) method to implement what the thread should do when it get started.
Once you have created the new Thread subclass, you can create an instance of it and then start a new thread by invoking the start (), which in turn calls run () method.
Let’s see an example for it.
import threading
import time

exitFlag = 0

class myThread (threading.Thread):
   def __init__(self, threadID, name, counter):
      threading.Thread.__init__(self)
      self.threadID = threadID
      self.name = name
      self.counter = counter
   def run(self):
      print ("Starting " + self.name)
      print_time(self.name, 5, self.counter)
      print ("Exiting " + self.name)

def print_time(threadName, counter, delay):
   while counter:
      if exitFlag:
         threadName.exit()
      time.sleep(delay)
      print ("%s: %s" % (threadName, time.ctime(time.time())))
      counter -= 1

# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

# Start new Threads
thread1.start()
thread2.start()

print ("Exiting Main Thread")
When I run the above code, I received the following output.
Starting Thread-1
Starting Thread-2
Exiting Main Thread
Thread-1: Sat Jan  1 11:56:43 2022
Thread-1: Sat Jan  1 11:56:44 2022
Thread-2: Sat Jan  1 11:56:44 2022
Thread-1: Sat Jan  1 11:56:45 2022
Thread-1: Sat Jan  1 11:56:46 2022
Thread-2: Sat Jan  1 11:56:46 2022
Thread-1: Sat Jan  1 11:56:47 2022
Exiting Thread-1
Thread-2: Sat Jan  1 11:56:48 2022
Thread-2: Sat Jan  1 11:56:50 2022
Thread-2: Sat Jan  1 11:56:52 2022
Exiting Thread-2

How to Synchronize the Threads?

          Python threading module provide a simple-to-implement locking mechanism that allows you to synchronize the threads. Here, a new lock is created by calling the Lock () method, which returns the new lock.
The acquire(blocking) method of the new lock object is then used to force the threads to run synchronously. There is an optional blocking parameter which help you to enablesto control whether the thread waits to acquire the lock.
If you setblocking to 0, the thread returns immediately with a 0 value if the lock cannot be acquired and with a 1 if the lock was acquired. If blocking is set to 1, the thread blocks and wait for the lock to be released.
The release () method of the new lock object is used to release the lock when it is no longer required.
Let’s take an example:
import threading
import time

class myThread (threading.Thread):
   def __init__(self, threadID, name, counter):
      threading.Thread.__init__(self)
      self.threadID = threadID
      self.name = name
      self.counter = counter
   def run(self):
      print ("Starting " + self.name)
      # Get lock to synchronize threads
      threadLock.acquire()
      print_time(self.name, self.counter, 3)
      # Free lock to release next thread
      threadLock.release()

def print_time(threadName, delay, counter):
   while counter:
      time.sleep(delay)
      print ("%s: %s" % (threadName, time.ctime(time.time())))
      counter -= 1

threadLock = threading.Lock()
threads = []

# Create new threads
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)

# Start new Threads
thread1.start()
thread2.start()

# Add threads to thread list
threads.append(thread1)
threads.append(thread2)

# Wait for all threads to complete
for t in threads:
    t.join()
print ("Exiting Main Thread")
If we run the above code, the following results is obtained
Starting Thread-1
Starting Thread-2
Thread-1: Sat Jan  1 11:58:12 2022
Thread-1: Sat Jan  1 11:58:13 2022
Thread-1: Sat Jan  1 11:58:14 2022
Thread-2: Sat Jan  1 11:58:16 2022
Thread-2: Sat Jan  1 11:58:18 2022
Thread-2: Sat Jan  1 11:58:20 2022
Exiting Main Thread

How to set Multithreaded Priority Queue?

          There is another module known as Queue module which allows you to create a new queue object that can hold a specific number of items. Below are some of the following methods to control the Queue −
·        get() − The get() removes and returns an item from the queue.
·        put() − The put adds item to a queue.
·        qsize() − The qsize() returns the number of items that are currently in the queue.
·        empty() − The empty( ) returns true if queue is empty; otherwise, false.
·        full() − the full() returns true if queue is full; otherwise, false.
Let’s see an example for it.
import queue
import threading
import time

exitFlag = 0

class myThread (threading.Thread):
   def __init__(self, threadID, name, q):
      threading.Thread.__init__(self)
      self.threadID = threadID
      self.name = name
      self.q = q
   def run(self):
      print ("Starting " + self.name)
      process_data(self.name, self.q)
      print ("Exiting " + self.name)

def process_data(threadName, q):
   while not exitFlag:
        queueLock.acquire()
        if not workQueue.empty():
            data = q.get()
            queueLock.release()
            print ("%s processing %s" % (threadName, data))
        else:
            queueLock.release()
        time.sleep(1)

threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock()
workQueue = queue.Queue(10)
threads = []
threadID = 1

# Create new threads
for tName in threadList:
   thread = myThread(threadID, tName, workQueue)
   thread.start()
   threads.append(thread)
   threadID += 1

# Fill the queue
queueLock.acquire()
for word in nameList:
   workQueue.put(word)
queueLock.release()

# Wait for queue to empty
while not workQueue.empty():
   pass

# Notify threads it's time to exit
exitFlag = 1

# Wait for all threads to complete
for t in threads:
   t.join()
print ("Exiting Main Thread")
When we run the above code, we get the following output.
Starting Thread-1
Starting Thread-2
Starting Thread-3
Thread-3 processing One
Thread-1 processing Two
Thread-2 processing Three
Thread-3 processing Four
Thread-1 processing Five
Exiting Thread-2
Exiting Thread-3
Exiting Thread-1
Exiting Main Thread
I hope after reading this article, finally, you came to know about HowMultithreaded Programming can be done in Python, how you can Synchronize the Threads and how to set Multithreaded Priority Queue in python.
  
Enjoyed reading this blog? Then why not share it with others. Help us make this AI community stronger. 
To learn more about such concepts related to Artificial Intelligence, visit our insideAIML blog page.
You can also ask direct queries related to Artificial Intelligence, Deep Learning, Data Science and Machine Learning on our live insideAIML discussion forum.
Keep Learning. Keep Growing. 

Submit Review