Functional Python Programming

(Wang) #1

The Multiprocessing and Threading Modules


Multiple threads, on the other hand, are part of a single process; all threads of a
process share OS resources. We can make an exception to get some thread-local
memory that can be freely written without interference from other threads. Outside
thread-local memory, operations that write to memory can set the internal state
of the process in a potentially unpredictable order. Explicit locking must be used
to avoid problems with these stateful updates. As noted previously, the overall
sequence of instruction executions is rarely, strictly speaking, concurrent. The
instructions from concurrent threads and processes are generally interleaved in an
unpredictable order. With threading comes the possibility of destructive updates to
shared variables and the need for careful locking. With parallel processing come the
overheads of OS-level process scheduling.


Indeed, even at the hardware level, there are some complex memory write situations.
For more information on issues in memory writes, visit http://en.wikipedia.org/
wiki/Memory_disambiguation.


The existence of concurrent object updates is what raises havoc with trying to design
multithreaded applications. Locking is one way to avoid concurrent writes to shared
objects. Avoiding shared objects is another viable design technique. This is more
applicable to functional programming.


In CPython, the GIL is used to assure that OS thread scheduling will not interfere
with updates to Python data structures. In effect, the GIL changes the granularity of
scheduling from machine instructions to Python virtual machine operations. Without
the GIL, it's possible that an internal data structure might be corrupted by the
interleaved interaction of competing threads.


Where benefits will accrue


A program that does a great deal of calculation and relatively little I/O will not see
much benefit from concurrent processing. If a calculation has a budget of 28 minutes
of computation, then interleaving the operations in different ways won't have very
much impact. Switching from strict to non-strict evaluation of 100 billion bytecodes
won't shrink the elapsed execution time.


However, if a calculation involves a great deal of I/O, then interleaving CPU
processing and I/O requests can have an impact on performance. Ideally, we'd like
to do our computations on some pieces of data while waiting for the OS to complete
input of the next pieces of data.

Free download pdf