In other words, this script simply provides methods expected by the Thread framework.
The advantage of taking this more coding-intensive route is that we get both per-thread
state information (the usual instance attribute namespace), and a set of additional
thread-related tools from the framework “for free.” The Thread.join method used near
the end of this script, for instance, waits until the thread exits (by default); we can use
this method to prevent the main thread from exiting before its children, rather than
using the time.sleep calls and global locks and variables we relied on in earlier threading
examples.
The example script also uses threading.Lock to synchronize stream access as before
(though this name is really just a synonym for _thread.allocate_lock in the current
implementation). The threading module may provide the extra structure of classes, but
it doesn’t remove the specter of concurrent updates in the multithreading model in
general.
Other ways to code threads with threading
The Thread class can also be used to start a simple function, or any other type of callable
object, without coding subclasses at all—if not redefined, the Thread class’s default
run method simply calls whatever you pass to its constructor’s target argument, with
any provided arguments passed to args (which defaults to () for none). This allows us
to use Thread to run simple functions, too, though this call form is not noticeably sim-
pler than the basic _thread module. For instance, the following code snippets sketch
four different ways to spawn the same sort of thread (see four-threads*.py in the exam-
ples tree; you can run all four in the same script, but would have to also synchronize
prints to avoid overlap):
import threading, _thread
def action(i):
print(i ** 32)
# subclass with state
class Mythread(threading.Thread):
def __init__(self, i):
self.i = i
threading.Thread.__init__(self)
def run(self): # redefine run for action
print(self.i ** 32)
Mythread(2).start() # start invokes run()
# pass action in
thread = threading.Thread(target=(lambda: action(2))) # run invokes target
thread.start()
# same but no lambda wrapper for state
threading.Thread(target=action, args=(2,)).start() # callable plus its args
# basic thread module
_thread.start_new_thread(action, (2,)) # all-function interface
Threads | 201