This is an excerpt from Wesley Chun's recent book Core Python Applications Programming
> With Python you can start a thread, but you can’t stop it.
> Sorry. You’ll have to wait until it reaches the end of execution.
So, just the same as [comp.lang.python], then?
—Cliff Wells, Steve Holden (and Timothy Delaney), February 2002
4.1 Introduction/Motivation 157
In this section, we will explore the different ways by which you can achieve more parallelism in your code. We will begin by differentiating between processes and threads in the first few of sections of this chapter. We will then introduce the notion of multithreaded programming and present some multithreaded programming features found in Python. (Those of you already familiar with multithreaded programming can skip directly to Section 4.3.5.) The final sections of this chapter present some examples of how to use the threading and Queue modules to accomplish multithreaded programming with Python.[...]
4.6 Comparing Single vs. Multithreaded Execution
The mtfacfib.py script, presented in Example 4-8 compares execution of
the recursive Fibonacci, factorial, and summation functions. This script runs
all three functions in a single-threaded manner. It then performs the same task
by using threads to illustrate one of the advantages of having a threading
Example 4-8 Fibonacci,
Factorial, Summation (mtfacfib.py)
single-threaded fashion, followed by the alternative with multiple threads.
#!/usr/bin/env python from myThread import MyThread from time import ctime, sleep def fib(x): sleep(0.005) if x < 2: return 1 return (fib(x-2) + fib(x-1)) def fac(x): sleep(0.1) if x < 2: return 1 return (x * fac(x-1)) def sum(x): sleep(0.1) if x < 2: return 1 return (x + sum(x-1)) funcs = [fib, fac, sum] n = 12 def main(): nfuncs = range(len(funcs)) print '*** SINGLE THREAD' for i in nfuncs: print 'starting', funcs[i].__name__, 'at:', \ ctime() print funcs[i](n) print funcs[i].__name__, 'finished at:', \ ctime() print '\n*** MULTIPLE THREADS' threads =  for i in nfuncs: t = MyThread(funcs[i], (n,), funcs[i].__name__) threads.append(t) for i in nfuncs: threads[i].start() for i in nfuncs: threads[i].join() print threads[i].getResult() print 'all DONE' if __name__ == '__main__': main()
Running in single-threaded mode simply involves calling the functions one at a time and displaying the corresponding results right after the function call.
When running in multithreaded mode, we do not display the result right away. Because we want to keep our MyThread class as general as possible (being able to execute callables that do and do not produce output), we wait until the end to call the getResult() method to finally show you the return values of each function call.
Because these functions execute so quickly (well, maybe except for the Fibonacci function), you will notice that we had to add calls to sleep() to each function to slow things down so that we can see how threading can improve performance, if indeed the actual work had varying execution times—you certainly wouldn’t pad your work with calls to sleep(). Anyway, here is the output:
*** SINGLE THREAD
starting fib at: Wed Nov 16 18:52:20 2011
fib finished at: Wed Nov 16 18:52:24 2011
starting fac at: Wed Nov 16 18:52:24 2011
fac finished at: Wed Nov 16 18:52:26 2011
starting sum at: Wed Nov 16 18:52:26 2011
sum finished at: Wed Nov 16 18:52:27 2011
*** MULTIPLE THREADS
starting fib at: Wed Nov 16 18:52:27 2011
starting fac at: Wed Nov 16 18:52:27 2011
starting sum at: Wed Nov 16 18:52:27 2011
fac finished at: Wed Nov 16 18:52:28 2011
sum finished at: Wed Nov 16 18:52:28 2011
fib finished at: Wed Nov 16 18:52:31 2011
The full chapter's table of contents include:
- Threads and Processes
- Threads and Python
- The thread Module
- The threading Module
- Comparing Single vs. Multithreaded Execution
- Multithreading in Practice
- Producer-Consumer Problem and the Queue/queue Module
- Alternative Considerations to Threads
- Related Modules