Section 14.4. The threading Module


14.4. The threading Module

The threading module is built on top of module thread and supplies multithreading functionality in a more usable, higher-level 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 (which means 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, threading supplies the currentThread factory function.

currentThread

currentThread( )

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 (nondaemon) thread keeps Python alive until the thread terminates. Class Thread exposes the following constructor and methods.

Thread

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 that 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.

getName, setName

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.

isAlive

t.isAlive( )

Returns TRue if t is active (i.e., if t.start has executed and t.run has not yet terminated). Otherwise, isAlive returns False.

isDaemon, setDaemon

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 that creates t is a daemon. You can call t.setDaemon only before t.start; it sets t to be a daemon if daemonic is true.

join

t.join(timeout=None)

The calling thread (which must not be t) suspends until t terminates. timeout is covered in "Timeout parameters" on page 346. You can call t.join only after t.start.

run

t.run( )

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

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" on page 350 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 an optional timeout argument. A Thread object's join method also accepts an optional 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 it is not None, a timeout argument is a floating-point value that indicates an interval of time in seconds (timeout can have a fractional part, so it 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" on page 341. RLock objects supply the same methods as Lock objects. The semantics of an RLock object r are, however, often more convenient. An RLock is a "re-entrant" lock, meaning that 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 (covered in "try/finally" on page 123) is a good way to ensure the lock is indeed released (in Python 2.5, the new with statement, covered in "The with statement" on page 125, is generally at least as good).

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.

Condition

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.

acquire, release

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.

notify, notifyAll

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

c.wait(timeout=None)

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 in "Timeout parameters" on page 346. 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 can 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 any other thread calls e.set( ). e has a flag that records whether the event happened; it is 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 brittle for more general use; in particular, relying on calls to e.clear( ) is error-prone. Class Event exposes the following methods.

Event

class Event( )

Event creates and returns a new Event object e, with e's flag set to False.

clear

e.clear( )

Sets e's flag to False.

isSet

e.isSet( )

Returns the value of e's flag, true or False.

set

e.set( )

Sets e's flag to true. All threads waiting on e, if any, become ready to run.

wait

e.wait(timeout=None)

If e's flag is true, wait returns immediately. Otherwise, wait suspends the calling thread until some other thread calls set. timeout is covered in "Timeout parameters" on page 346.


14.4.2.5. Semaphore objects

Semaphores (also known as counting 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., 4 printers or 20 sockets), although it's often more robust to use Queues for such purposes.

Semaphore

class Semaphore(n=1)

Semaphore creates and returns a semaphore object s with the state set to n. A semaphore object s exposes the following methods.

acquire

s.acquire(wait=TRue)

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.

release

s.release( )

When s's state is > 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.


14.4.3. Thread Local Storage

In Python 2.4, module threading supplies a class local, which threads can use to obtain thread-local storage (TLS), also known as per-thread data. An instance L of local has arbitrary named attributes that you can set and get, and stores them in a dictionary L._ _dict_ _ that you can also access. L is fully thread-safe, meaning there is no problem if multiple threads simultaneously set and get attributes on L. Most important, each thread that accesses L sees a completely disjoint set of attributes, and any changes made in one thread have no effect in other threads. For example:

 import threading L = threading.local( ) print 'in main thread, setting zop to 42' L.zop = 42 def targ( ):   print 'in subthread, setting zop to 23'   L.zop = 23   print 'in subthread, zop is now', L.zop t = threading.Thread(target=targ) t.start( ) t.join( ) print 'in main thread, zop is now', L.zop # emits: # in main thread, setting zop to 42 # in subthread, setting zop to 23 # in subthread, zop is now 23 # in main thread, zop is now 42 

TLS makes it easier for you to write code meant to run in multiple threads, since you can use the same namespace (an instance of threading.local) in multiple threads without the separate threads interfering with each other.




Python in a Nutshell
Python in a Nutshell, Second Edition (In a Nutshell)
ISBN: 0596100469
EAN: 2147483647
Year: 2004
Pages: 192
Authors: Alex Martelli

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net