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.