Monday, August 31, 2020

Multithreading Programing in Python



Hello dear readers! welcome back to another section of my tutorial on Python. In this tutorial post, we are going to be discussing about Multithreading in Python.

Running serveral threads is like running many various programs at the same time, but with the following benefits -

  • Multiple threads within a process do share the same data space with the main thread and can therefore share information or easily communicate with each other than if they were in separate processes.
  • Threads at times called light-weight processes and they do not need much memory overhead; they are cheaper than processes.


A thread has a beginning, an execution sequence and also a conclusion. It has an instruction pointer that keeps track of where it is currently running within its context.

  • It can be be interrupted.
  • It can temporarily be placed on hold while other threads are running (this is called yielding).

Starting a New Thread

To start up a new thread, you need to call the following methods available in the thread module -

Syntax

Following is the syntax for starting a new thread and the needed methods -

thread.start_new_thread ( function, args[, kwargs] )

This method call enables a fast and efficient way to create new threads in both Windows and Linux.


The method call returns instantly and the child thread starts and calls function with the passed list of args. When the function returns, the thread terminates.

Here, args is a tuple of arguments; use an empty tuple to call a function without passing any arguments to it. Here kwargs is an optional dictionary of keyword arguments.

Example

The following below is a simple example -

#!/usr/bin/python

import thread
import time

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

# Create two threads as follows
try:
   thread.start_new_thread( print_time, ("Thread-1", 2, ) )
   thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
   print "Error: unable to start thread"

while 1:
   pass

Output

When the above code is executed, it will produce the following result -

Thread-1: Mon Aug 31 15:42:17 2020
Thread-1: Mon Aug 31 15:42:19 2020
Thread-2: Mon Aug 31 15:42:19 2020
Thread-1: Mon Aug 31 15:42:21 2020
Thread-2: Mon Aug 31 15:42:23 2020
Thread-1: Mon Aug 31 15:42:23 2020
Thread-1: Mon Aug 31 15:42:25 2020
Thread-2: Mon Aug 31 15:42:27 2020
Thread-2: Mon Aug 31 15:42:31 2020
Thread-2: Mon Aug 31 15:42:35 2020

Although it is extremely effective for low-level threading, but the threading module is very limited compared to the new threading module.



The Threading Functions

The newer threading functions included in the Python version 2.4 provides much more powerful, high-level support for threads than the threading module that was discussed above.

The threading module reveals all the the methods of the thread module as well as providing some additional methods.

threading.activeCount()

This method returns the number of thread objects that are active.

threading.currentThread()

This method returns the number of thread objects in the caller's thread control.

threading.enumerate()

This function returns the list of all the thread objects currently active.


In addition to the above methods, the thread module has the Thread class that implements threading. Here are the methods provided by the Thread class -

  • run() - This method is the entry point of a thread.
  • start() - This method starts a thread by calling the run method
  • join([time]) - This method waits for the threads to terminate.
  • isAlive() - This function checks if a thread is still executing.
  • getName() - This method returns the name of a thread.
  • setName() - This function sets the name of a thread.


Creating Threads using Threading Module

To implement a new thread using the threading module, you have to do the following -

  • Define a new subclass of the Thread class.
  • Override __init__(self [, args]) method to add additional arguments.
  • Finally, override the run(self [, args]) method to implement what should be done by the thread when started.

Once you are done creating the new Thread subclass, you can create an instance of it and then begin a new thread by calling the start() method, which in turn calls the run() method.

Example

The following below is a simple example -

#!/usr/bin/python

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"

Output

When the above code is executed, it will produce the following result -

Starting Thread-1
Starting Thread-2
Exiting Main Thread
Thread-1: Mon Aug 31 09:10:03 2020
Thread-1: Mon Aug 31 09:10:04 2020
Thread-2: Mon Aug 31 09:10:04 2020
Thread-1: Mon Aug 31 09:10:05 2020
Thread-1: Mon Aug 31 09:10:06 2020
Thread-2: Mon Aug 31 09:10:06 2020
Thread-1: Mon Aug 31 09:10:07 2020
Exiting Thread-1
Thread-2: Mon Aug 31 09:10:08 2020
Thread-2: Mon Aug 31 09:10:10 2020
Thread-2: Mon Aug 31 09:10:12 2020
Exiting Thread-2



Synchronizing Threads
The threading module provided with Python includes a simple-to-implement locking mechanism that allows you to synchronize threads. A new lock is created by calling the lock() method, which returns the new lock.

The acquire() Method
The acquire(blocking) method of the new lock object is used in forcing the threads to run synchronously. In this method, the blocking parameter is optional and it enables you to control whether the thread waits to acquire the lock.

If blocking parameter is set to 0, the thread returns immediately with a 0 value if the lock can not be acquired and with 1 if the lock was acquired. If blocking is set to 1, then the thread blocks and waits for the lock to be released.

The release() Method
The release function of the new lock object is utilized in releasing the lock whenever it is no longer required

Example
The following below is a simple example -

#!/usr/bin/python

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"

Output
When the above code is executed, it will produce the following result -

Starting Thread-1
Starting Thread-2
Thread-1: Mon Aug 31 09:11:28 2020
Thread-1: Mon Aug 31 09:11:29 2020
Thread-1: Mon Aug 31 09:11:30 2020
Thread-2: Mon Aug 31 09:11:32 2020
Thread-2: Mon Aug 31 09:11:34 2020
Thread-2: Mon Aug 31 09:11:36 2020
Exiting Main Thread



Multithreaded Priority Queue
The Queue module allows you to create a new queue object that can hold a specific number of items. Following below are the methods to control the Queue -

  • get() - The get() method removes and returns an item from the queue.
  • put() - The put() method adds item to the queue.
  • qsize() - The qsize() method returns the number of items currently in the queue.
  • empty() - This function returns True if the queue is empty, else False.
  • full() - The full() method returns True if queue is full, else False.

Example
#!/usr/bin/python

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"

Output
When the above code is executed, it will produce the following result -

Starting Thread-1
Starting Thread-2
Starting Thread-3
Thread-1 processing One
Thread-2 processing Two
Thread-3 processing Three
Thread-1 processing Four
Thread-2 processing Five
Exiting Thread-3
Exiting Thread-1
Exiting Thread-2
Exiting Main Thread


Alright guys! This is where we are rounding up for this tutorial post. In my next tutorial, we are going to be discussing about the Python XML Processing.

Feel feel to ask your questions where necessary and i will attend to them as soon as possible. If this tutorial was helpful to you, you can use the share button to share this tutorial.

Follow us on our various social media platforms to stay updated with our latest tutorials. You can also subscribe to our newsletter in order to get our tutorials delivered directly to your emails.

Thanks for reading and bye for now.
Share:

0 comments:

Post a Comment

Hello dear readers! Please kindly try your best to make sure your comments comply with our comment policy guidelines. You can visit our comment policy page to view these guidelines which are clearly stated. Thank you.