14.4 The threading Module
The threading module
is built on top of module thread and supplies
multithreading functionality in a more usable form. The general
approach of threading is similar to that of Java,
but locks and conditions are modeled as separate objects (in Java,
such functionality is part of every object), and threads cannot be
directly controlled from the outside (meaning there are no
priorities, groups, destruction, or stopping). All methods of objects
supplied by threading are
atomic.
threading provides numerous classes for dealing
with threads, including Thread,
Condition, Event,
RLock, and Semaphore. Besides
factory functions for the classes detailed in the following sections
of this chapter, threading supplies the
currentThread factory
function.
Returns a Thread object for the calling thread. If
the calling thread was not created by module
threading, currentThread
creates and returns a semi-dummy Thread object
with limited functionality.
14.4.1 Thread Objects
A Thread object
t models a thread. You can pass
t's main function as an
argument when you create t, or you can
subclass Thread and override the
run method (you may also override _
_init_ _, but should not override other methods).
t is not ready to run when you create it:
to make t ready (active), call
t.start( ). Once
t is active, it terminates when its main
function ends, either normally or by propagating an exception. A
Thread t can be a
daemon, meaning that Python can terminate even if
t is still active, while a normal
(non-daemon) thread keeps Python alive until the thread terminates.
Class Thread exposes the following constructor and
methods.
class Thread(name=None,target=None,args=( ),kwargs={ })
|
|
Always call Thread with named arguments: the
number and order of formal arguments may change in the future, but
the names of existing arguments are guaranteed to stay. When you
instantiate class Thread itself, you should
specify target:
t.run calls
target(*args,**kwargs).
When you subclass Thread and override
run, you normally don't specify
target. In either case, execution
doesn't begin until you call
t.start( ).
name is
t's name. If
name is None,
Thread generates a unique name for
t. If a subclass T of
Thread overrides _ _init_ _,
T._ _init_ _ must call Thread._ _init_
_ on self before any other
Thread method.
t.getName( )
t.setName(name)
|
|
getName returns
t's name, and
setName rebinds
t's name. The
name string is arbitrary, and a
thread's name need not be unique among threads.
Returns True if t is
active (i.e., if
t.start has executed
and t.run has not yet
terminated). Otherwise, isAlive returns
False.
t.isDaemon( )
t.setDaemon(daemonic)
|
|
isDaemon returns True if
t is a daemon (i.e., Python can terminate
the whole process even if t is still
active—such a termination also terminates
t); otherwise isDaemon
returns False. Initially,
t is a daemon if and only if the thread
creating t is a daemon. You can call
t.setDaemon only before
t.start: it sets
t to be a daemon if
daemonic is true.
The calling thread (which must not be t)
suspends until t terminates.
timeout is covered in the upcoming section
Section 14.4.2.1. You can call
t.join only after
t.start.
run
is the
method that executes t's
main function. Subclasses of Thread often override
run. Unless overridden, run
calls the target callable passed on
t's creation. Do
not call
t.run
directly—calling
t.run appropriately is
the job of t.start!
start
makes t active and arranges for
t.run to execute in a
separate thread. You must call
t.start only once for
any given thread object t.
14.4.2 Thread Synchronization Objects
The
threading module supplies several synchronization
primitives, which are objects that let threads communicate and
coordinate. Each primitive has specialized uses. However, as long as
you avoid global variables that several threads access,
Queue can often provide all the coordination you
need. "Threaded Program
Architecture" later in this chapter shows how to use
Queue objects to give your multithreaded programs
simple and effective architectures, often without needing any
synchronization primitives.
14.4.2.1 Timeout parameters
Synchronization primitives Condition and
Event supply wait methods that
accept a timeout argument. A
Thread object's
join method also accepts a
timeout argument. A
timeout argument can be
None, the default, to obtain normal blocking
behavior (the calling thread suspends and waits until the desired
condition is met). If not None, a
timeout argument is a floating-point value
that indicates an interval of time in seconds
(timeout can have a fractional part and so
can indicate any time interval, even a very short one). If
timeout seconds elapse, the calling thread
becomes ready again, even if the desired condition has not been met.
timeout lets you design systems that are
able to overcome occasional anomalies in one or a few threads, and
thus are more robust. However, using
timeout may also make your program
slower.
14.4.2.2 Lock and RLock objects
The Lock objects
exposed by module threading are the same as those
supplied by module thread and covered in
"The thread Module" earlier in this
chapter. RLock objects supply the same methods as
Lock objects. The semantics of an
RLock object r are,
however, often more convenient. When r is
locked, it keeps track of the owning thread (i.e., the thread that
locked it). The owning thread can call
r.acquire again without
blocking: r just increments an internal
count. In a similar situation involving a Lock
object, the thread would block forever (until the lock is released by
some other thread).
An RLock object r is
unlocked only when release has been called as many
times as acquire. Only the thread owning
r should call
r.release. An
RLock is useful to ensure exclusive access to an
object when the object's methods call each other;
each method can acquire at the start, and release at the end, the
same RLock instance.
try/finally is a good way to
ensure the lock is indeed released.
14.4.2.3 Condition objects
A Condition object
c wraps a Lock or
RLock object L. Class
Condition exposes the following constructor and
methods.
class Condition(lock=None)
|
|
Condition creates and returns a new
Condition object c with
the lock L set to
lock. If lock
is None, L is set to a
newly created RLock object.
c.acquire(wait=1)
c.release( )
|
|
These methods call
L's corresponding
methods. A thread must never call any other method on
c unless the thread holds lock
L.
c.notify( )
c.notifyAll( )
|
|
notify wakes up one of the threads waiting on
c. The calling thread must hold
L before it calls
c.notify( ), and
notify does not release
L. The woken-up thread does not become
ready until it can acquire L again.
Therefore, the calling thread normally calls
release after calling notify.
notifyAll is like notify, but
wakes up all waiting threads, not just one.
wait releases L, then
suspends the calling thread until some other thread calls
notify or notifyAll on
c. The calling thread must hold
L before it calls
c.wait( ).
timeout is covered earlier in Section 14.4.2.1. After a thread wakes up,
either by notification or timeout, the thread becomes ready when it
acquires L again. When
wait returns, the calling thread always holds
L again.
In typical use, a Condition object
c regulates access to some global state
s that is shared between threads. When a
thread needs to wait for s to change, the
thread loops as follows:
c.acquire( )
while not is_ok_state(s):
c.wait( )
do_some_work_using_state(s)
c.release( )
Meanwhile, each thread that modifies s
calls notify (or notifyAll, if
it needs to wake up all waiting threads, not just one) each time
s changes:
c.acquire( )
do_something_that_modifies_state(s)
c.notify( ) # or, c.notifyAll( )
c.release( )
As you see, you always need to acquire and release
c around each use of
c's methods, which makes
using Condition somewhat error-prone.
14.4.2.4 Event objects
Event objects let any number of threads
suspend and wait. All threads waiting on Event
object e become ready when some other
thread calls e.set( ).
e has a flag recording whether the event
happened, initially False when
e is created. Event is
thus a bit like a simplified Condition. Event
objects are useful to signal one-shot changes, but are brittle for
more general uses, as resetting an event object (i.e., relying on
calls to e.clear( )) is
quite error-prone. Class Event exposes the
following methods.
Event creates and returns a new
Event object e.
Sets e's flag to
False.
Returns the value of e's
flag, True or False.
Sets e's flag to
True. All threads waiting on
e, if any, become ready to run.
If e's flag is
True, wait returns immediately.
Otherwise, wait suspends the calling thread until
some other thread calls set.
timeout is covered earlier in Section 14.4.2.1.
14.4.2.5 Semaphore objects
Semaphores are a generalization of
locks. The state of a Lock can be seen as
True or False; the state of a
Semaphore s is a number
between 0 and some n
set when s is created. Semaphores can be
useful to manage a fixed pool of resources (e.g., four printers or
twenty sockets), although it's often more robust to
use a Queue. A semaphore object
s exposes the following methods.
Semaphore
creates and returns a semaphore object
s with the state set to
n.
When s's state is greater
than 0, acquire decrements the
state by 1 and returns True.
When s's state is
0 and wait is
True, acquire suspends the
calling thread and waits until some other thread calls
s.release. When
s's state is
0 and wait is
False, acquire immediately
returns False.
When s's state is greater
than 0 or when the state is 0
but no thread is waiting on s,
release increments the state by
1. When
s's state is
0 and some thread is waiting on
s, release leaves
s's state at
0 and wakes up an arbitrary waiting thread. The
thread that calls release is not suspended: it
remains ready and continues to execute normally.
|