RSS

Threading in Python

11 Dec

It will be better for us if we directly start with an example. After every small patch of code, I have tried to explain what, how and why.

Let us start considering basic producer-consumer problem using thread module

import thread
import time

# Define a function for the thread
def process(person, delay):
    count = 0
    while count < 5:
        time.sleep(delay)
        count += 1
        #material = count
        print "%s material %s at time %s" % (person, count, time.ctime(time.time()))

# Create two threads as follows
try:
    thread.start_new_thread( process, ("Producer produces", 1, ) )
    thread.start_new_thread( process, ("Consumer consumes", 2, ) )
except:
    print "Error: unable to start thread"

while 1:
    pass

Output

Screenshot from 2012-12-11 14:02:25

In the above example we spawn 2 new threads using following method available in thread module

thread.start_new_thread(function, arguments_in_tuple_form)

Creating Thread 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 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() or run() methods.

Now we will see the same producer consumer example by using Threading module

import threading
import time

class myThread (threading.Thread):
    def __init__(self, person, delay):
        threading.Thread.__init__(self)
        self.person = person
        self.delay = delay

    def run(self):
        process(self.person, self.delay)

def process(threadName, delay):
    counter = 1
    while counter <= 5:
        material = counter
        time.sleep(delay)
        print "%s material %s at time %s" % (threadName,
                                             material,
                                             time.ctime(time.time()),)
        counter += 1

# Create new threads
thread1 = myThread("Producer produces", 1)
thread2 = myThread("Consumer consumes", 2)

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

Output

Screenshot from 2012-12-11 14:02:13

Synchronizing threads

Currently, The Python Interpreter (Python 2.3.4) is not thread safe. There are no priorities, no thread groups. Threads cannot be stopped and suspended, resumed or interrupted. That is, the support provided is very much basic. However a lot can still be accomplished with this meager support, with the use of the threading module, as we shall see in the following sections. One of the main reasons is that in actuality only one thread is running at a time. This is because of some thing called a Global Interpreter Lock (GIL). In order to support multi-threaded Python programs, there’s a global lock that must be held by the current thread before it can safely access Python objects. Without the lock competing threads could cause havoc, for example: when two threads simultaneously increment the reference count of the same object, the reference count could end up being incremented only once instead of twice. Thus only the thread that has acquired the GIL may operate on Python Objects

import threading
import time

class myThread (threading.Thread):
    def __init__(self, person, delay):
        threading.Thread.__init__(self)
        self.person = person
        self.delay = delay

    def run(self):
        threadLock.acquire()
        process(self.person, self.delay)
        threadLock.release()

def process(threadName, delay):
    counter = 1
    while counter <= 5:
        material = counter
        time.sleep(delay)
        print "%s material %s at time %s" % (threadName,
                                             material,
                                             time.ctime(time.time()),)
        counter += 1

threadLock = threading.Lock()
threads = []

# Create new threads
thread1 = myThread("Producer produces", 1)
thread2 = myThread("Consumer consumes", 2)

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

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

# Wait for all threads to complete
try:
    for t in threads:
        t.join()
except:
    print ""

Look at lines 18 and 20 in the code. We acquired the lock and then thread did its work. Later we released the lock.

Output

Screenshot from 2012-12-11 14:01:18

 

I hope this post gave you a basic idea of how threading works in Python.

To read further, visit:
http://linuxgazette.net/107/pai.html
http://www.ibm.com/developerworks/aix/library/au-threadingpython/

 
2 Comments

Posted by on December 11, 2012 in Python

 

Tags: , , ,

2 responses to “Threading in Python

  1. Manoj Kumar

    December 26, 2012 at 7:19 am

    Hey , thanks for the simple explanation . I didnt get line 40 – 45 of the last part . Could you explain a bit whats the try – except for?

     
    • kunjkaria

      December 31, 2012 at 3:53 am

      That is the very essence of the code. Let us assume I need to spawn multiple threads to do the work, and continue to the next step only after all of them complete. I will need to tell the main thread to wait. The key point is to use Thread.join() method. .join() waits till the thread has finished executing.

       

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: