logo

Python Multithreading


Show

Running more than a few threads is alike executing numerous unlike programs alongside, but with the following reimbursement:

Multiple threads inside a procedure share a similar data space with the major thread and can consequently share information or converse with each other more effortlessly than if, they were divided processes.

Threads are little bits that are called lightweight procedures and they do not necessitate much memory in the clouds; they are cheaper than developments.

A thread has a start, an implementation series, and an end. It has a teaching pointer that stays track of where in its context it is at present running.

It can be pre-empted (interrupted)

It can provisionally be put on hold while other threads are administered - this is called yielding.

Starting a New Thread

To spawn another thread, you require to call the following technique obtainable in the thread module

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

This technique calls allows a fast and capable way to craft new threads in equally Linux and Windows.

The process call returns right away and the child thread creates and calls a function with the exceeded list of rags. When a function returns, the thread ends.

Here, rag is a tuple of arguments; employ an empty tuple to call a function with no short-lived arguments. kwargs is an elective dictionary of keyword arguments.

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

When the above code is executed, it produces the following result:

Thread-1: Thu Jan 22 15:42:17 2009
Thread-1: Thu Jan 22 15:42:19 2009
Thread-2: Thu Jan 22 15:42:19 2009
Thread-1: Thu Jan 22 15:42:21 2009
Thread-2: Thu Jan 22 15:42:23 2009
Thread-1: Thu Jan 22 15:42:23 2009
Thread-1: Thu Jan 22 15:42:25 2009
Thread-2: Thu Jan 22 15:42:27 2009
Thread-2: Thu Jan 22 15:42:31 2009
Thread-2: Thu Jan 22 15:42:35 2009

Although it is extremely effective for low-level threading, the thread module is very limited contrasted to the newer threading module.

The Threading Module

The newer threading module comprised of Python 2.4 offers a much influential, high-level hold-up for threads than the thread module talked about in the preceding section.

The threading module expose entire the methods of the thread module and distributes a number of additional methods -

  • threading.activeCount() - Returns the number of thread objects that are active.
  • threading.currentThread() - Returns the number of thread objects in the caller's thread control.
  • threading.enumerate() - 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.

Creating Thread Using Threading Module

To put into practice a new thread by the threading module, users have to do the following-

  • Define a new subclass of the Thread class.
  • Override the __init__(self [,args]) method to add additional arguments.

Then, supersede the run(self [,args]) way to implement what the thread must do when begun.

Once you have generated the new Thread subclass, you can form an occurrence of it and then begin a new thread by invoking the start (), which in turn calls run() method.

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"

When the above code is executed, it produces the following result:

Starting Thread-1
Starting Thread-2
Exiting Main Thread
Thread-1: Thu Mar 21 09:10:03 2013
Thread-1: Thu Mar 21 09:10:04 2013
Thread-2: Thu Mar 21 09:10:04 2013
Thread-1: Thu Mar 21 09:10:05 2013
Thread-1: Thu Mar 21 09:10:06 2013
Thread-2: Thu Mar 21 09:10:06 2013
Thread-1: Thu Mar 21 09:10:07 2013
Exiting Thread-1
Thread-2: Thu Mar 21 09:10:08 2013
Thread-2: Thu Mar 21 09:10:10 2013
Thread-2: Thu Mar 21 09:10:12 2013
Exiting Thread-2

Synchronizing Threads

The threading module offered with Python comprises a simple-to-implement locking device that agrees to you to harmonize threads. A new lock is produced by calling the Lock () way, which returns the new lock.

This acquired (blocking) method of the original lock object is employed to force threads to scuttle synchronously. The elective blocking parameter allows you to control whether the thread remains to obtain the lock.

If blocking is set 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.

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"

When the above code is executed, it produces the following result:

Starting Thread-1
Starting Thread-2
Thread-1: Thu Mar 21 09:11:28 2013
Thread-1: Thu Mar 21 09:11:29 2013
Thread-1: Thu Mar 21 09:11:30 2013
Thread-2: Thu Mar 21 09:11:32 2013
Thread-2: Thu Mar 21 09:11:34 2013
Thread-2: Thu Mar 21 09:11:36 2013
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. There are the following methods to control the Queue-

  • get() - The get() removes and returns an item from the queue.
  • put() - The put adds an 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 the queue is full; otherwise, 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"

When the above code is executed, it produces 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

Here at Intellinuts, we have created a complete Python tutorial for Beginners to get started in Python.