Python Threads |
Modified: |
Overview
Threads allow a program to perform multiple operations simultaneously and non-deterministically. A typical application needing multiple threads of execution is:
- one thread handles user input from mouse or keyboard
- a second thread is displaying a moving graphic such as a bouncing ball
The following is a quick look at Python threads.
Thread Example
The key point of example1.py is the call of the start() method which:
- calls run() method
- returns immediately
The effect is the main thread starts one thread running, returns to the for-statement to start another.
| # example0.py import time class example0 : def __init__( self, n ): self.N=n def run(self) : print 'Start number: ', self.N time.sleep(.01) print 'End number: ', self.N for i in range(5) : example0( i ).run(); |
# example1.py import threading import time class example1(threading.Thread) : def __init__( self, n ): threading.Thread.__init__(self) self.N=n def run(self) : print 'Start number: ', self.N time.sleep(.01) print 'End number: ', self.N for i in range(5) : example1( i ).start(); |
| Start number: 0 End number: 0 Start number: 1 End number: 1 Start number: 2 End number: 2 Start number: 3 End number: 3 Start number: 4 End number: 4 |
Start number: 0 Start number: 1 Start number: End number: 0 2 End number: 1 Start number: 3 End number: 2 Start number: 4 End number: >>> End number: 3 4 |
Serialization
In example1.py all threads execute with complete independence allowing for maximum parallelism. When multiple threads can operate on a common resource (e.g. printing to terminal output, changing a bank account balance), mutable access to the resource must be restricted to only a single thread at a time, called serialization.
Python provides a lock that when acquired prevents other threads from acquiring until the lock is released.
The example2.py has added a single, common lock, accessible to 0..4 threads, that ensures the statements executed between acquiring and releasing the lock are performed atomically (i.e. as one unit without other threads executing).
Note that the output of example2.py is almost the same as sequential execution because the threads do nothing else in the run() method. Note that the main thread does not acquire the lock so can execute on parallel with other threads.
| # example1.py import threading import time class example1(threading.Thread) : def __init__( self, n ): threading.Thread.__init__(self) self.N=n def run(self) : print 'Start number: ', self.N time.sleep(.01) print 'End number: ', self.N for i in range(5) : example1( i ).start(); |
# example2.py import threading import time class example2(threading.Thread) : def __init__( self, n ): threading.Thread.__init__(self) self.N=n def run(self) : lock.acquire() print 'Start number: ', self.N time.sleep(.01) print 'End number: ', self.N lock.release() lock=threading.Lock() for i in range(5) : example2( i ).start(); |
| Start number: 0 Start number: 1 Start number: End number: 0 2 End number: 1 Start number: 3 End number: 2 Start number: 4 End number: >>> End number: 3 4 |
Start number: 0 End number: >>> 0 Start number: 1 End number: 1 Start number: 2 End number: 2 Start number: 3 End number: 3 Start number: 4 End number: 4 |