Python Threading

The Python threading module provides an OOP solution to threading. The base class, threading.Thread, follows a Java like pattern to creating and joining threads. This post provides a threading demonstration with an example program found in Programming Python: Powerful Object-Oriented Programming.

Code

This is the example program with my own comments added.

import threading

# Thread is the base class for creating OOP Style Threads
# It has a run() method that contains the code that runs in a new thread
class MyThread(threading.Thread):
    def __init__(self, myId, count, mutex):
        self.myId = myId
        self.count = count
        self.mutex = mutex
        threading.Thread.__init__(self)

    # Everything inside of run is executed in a seperate thread
    def run(self):
        for i in range(self.count):
            with self.mutex:
                print('[{}] => {}'.format(self.myId, i))


if __name__ == '__main__':
    stdoutmutex = threading.Lock()
    threads = []
    for i in range(10):
        # Create the new Thread Object
        thread = MyThread(i, 100, stdoutmutex)
        
        # The thread doesn't actually start running until
        # start() is called
        thread.start()
        threads.append(thread)

    for thread in threads:
        # join() is used to synchronize threads
        # Calling join() on a thread makes the parent thread wait
        # until the child thread has finished
        thread.join()

    print('Main thread exiting...')

Explanation

The OOP approach to Python threads requires developers to extend the threading.Thread class. The Thread class provides high level methods that support threading such as start() and join() which we discuss shortly. It has also an empty run() method that developers need to override. All of the code placed in the run() method runs in a new thread.

We are still free to use locks with OOP threads. On line 20, we acquire a lock by calling threading.Lock(). The mutex is passed to the thread object’s constructor on line 24 and is used by the thread on line 15 to aquire a lock to that standard output stream.

It’s important to note that the new thread doesn’t actually run until we call start(). The start() method is what submits the thread to the thread pool so that the Python runtime can use the thread. Never call run() directly on thread object because doing so will keep the program single threaded. The run() method is called by the Python environment when it’s the thread’s turn to run.

The example program also uses the join() method. The join() method is used to make a parent thread wait until a child thread completes. The example program creates 10 threads and needs to wait until all of the threads are finished. This is done by entering a for-each loop on line 31 and then calling join() on each of the threads. When join() is called, the parent thread sleeps until child thread’s run() method is finished. When all 10 threads are finished, the program exits.

References

Lutz, Mark. Programming Python. Beijing, OReilly, 2013.

Advertisement

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 )

Connecting to %s

%d bloggers like this: