PYTHON MULTITHREADING - Complete Guide For Python Programming (2015)

Complete Guide For Python Programming (2015)

PYTHON MULTITHREADING

In python you can run multiple threads at a time. Running multiple threads is similar to running several different programs with following benefits:

• Multiple threads within a process share the same data space with the main thread and can share information or communicate with each other more easily as compared to when they were separate processes.

• Threads sometimes called light-weight processes and they don't require much memory overhead. A thread has 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 pre-empted.

• It can temporarily be put on hold while other threads are running, this method is called yielding.

Starting a New Thread:

To start a new thread, you need to call following method available in thread module:

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

This method is used to enable a fast and efficient way to create new threads in both Linux and Windows. The method call returns immediately and the child thread starts and calls function with the passed list of 'agrs'. When function returns, then the thread terminates. Here, 'args' is a tuple of arguments; that uses an empty tuple to call function without passing any arguments. 'kwargs' is an optional dictionary of keyword arguments.

For 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, ("MyThread-1", 2,) )

thread.start_new_thread( print_time, ("MyThread-2", 4,) )

except:

print "Error in starting a thread"

while 1:

pass

Output:

MyThread-1: Wed Jan 01:45 01:45:17 2015

MyThread-1: Wed Jan 01:45 01:45:19 2015

MyThread-2: Wed Jan 01:45 01:45:19 2015

MyThread-1: Wed Jan 01:45 01:45:21 2015

MyThread-2: Wed Jan 01:45 01:45:23 2015

MyThread-1: Wed Jan 01:45 01:45:23 2015

MyThread-1: Wed Jan 01:45 01:45:25 2015

MyThread-2: Wed Jan 01:45 01:45:27 2015

MyThread-2: Wed Jan 01:45 01:45:31 2015

MyThread-2: Wed Jan 01:45 01:45:35 2015

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

The Threading Module:

New threading module in Python 2.4 provides much more powerful, high-level support for threads. The threading module exposes all the methods of the thread module and provides some 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 given below:

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 ThreadingModule:

To implement a new thread using the threading module, you must follow the points given below:

• Define a new subclass of the Thread class.

• Override the __init__(self [,args]) method to add additional arguments.

• Then, override the run(self [,args]) method to implement what the thread should do when 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 will in turn call run() method.

For Example:

#!/usr/bin/python

import threading

import time

exitFlag = 0

class myBook (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, self.counter, 5)

print "Exiting " + self.name

def print_time(threadName, delay, counter):

while counter:

if exitFlag:

thread.exit()

time.sleep(delay)

print "%s: %s" % (threadName, time.ctime(time.time()))

counter -= 1

# Create new threads

thread1 = myBook(1, "MyThread-1", 1)

thread2 = myBook(2, "MyThread-2", 2)

# Start new Threads

thread1.start()

thread2.start()

print "Exit From Main Thread"

Output:

Starting MyThread-1

Starting MyThread-2

Exit From Main Thread

MyThread-1: Mon Jul 27 01:45:10:03 2015

MyThread-1: Mon Jul 27 01:45:10:04 2015

MyThread-2: Mon Jul 27 01:45:10:04 2015

MyThread-1: Mon Jul 27 01:45:10:05 2015

MyThread-1: Mon Jul 27 01:45:10:06 2015

MyThread-2: Mon Jul 27 01:45:10:06 2015

MyThread-1: Mon Jul 27 01:45:10:07 2015

Exiting MyThread-1

MyThread-2: Mon Jul 27 01:45:10:08 2015

MyThread-2: Mon Jul 27 01:45:10:10 2015

MyThread-2: Mon Jul 27 01:45:10:12 2015

Exiting MyThread-2

Synchronizing Threads:

In python threading module includes a simple-to-implement locking mechanism which will allow you to synchronize the threads. A new lock is created by calling the Lock() method, which returns the new lock. to force threads to run, The acquire(blocking) method of the new lock object is used. If blocking is set to 0, the thread will return 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 will block and wait for the lock to be released. The release() method of the the new lock object would be used to release the lock when it is no longer required.

For Example:

#!/usr/bin/python

import threading

import time

class myBook (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 = myBook(1, "MyThread-1", 1)

thread2 = myBook(2, "MyThread-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 from Main Thread"

Output:

Starting MyThread-2

MyThread-1: Mon Jul 27 01:45:11:28 2015

MyThread-1: Mon Jul 27 01:45:11:29 2015

MyThread-1: Mon Jul 27 01:45:11:30 2015

MyThread-2: Mon Jul 27 01:45:11:32 2015

MyThread-2: Mon Jul 27 01:45:11:34 2015

MyThread-2: Mon Jul 27 01:45:11:36 2015

Exiting from Main Thread

Multithreaded Priority Queue:

The Queue module in python allows you to create a new queue object, which can hold a specific number of items. Methods that are used to control the Queue are given below:

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.

For Example:

#!/usr/bin/python

import Queue

import threading

import time

exitFlag = 0

class myBook (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 = ["MyThread-1", "MyThread-2", "Thread-3"]

nameList = ["A", "B", "C", "D", "E"]

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:

Starting Thread-1

Starting Thread-2

Starting Thread-3

Thread-1 processing A

Thread-2 processing B

Thread-3 processing C

Thread-1 processing D

Thread-2 processing E

Exiting Thread-3

Exiting Thread-1

Exiting Thread-2

Exiting Main Thread