Expand the multiprocessing section
This commit is contained in:
parent
8ea605c204
commit
4ec0c27eea
|
@ -526,28 +526,152 @@ environment variable.
|
||||||
PEP 371: The ``multiprocessing`` Package
|
PEP 371: The ``multiprocessing`` Package
|
||||||
=====================================================
|
=====================================================
|
||||||
|
|
||||||
.. XXX I think this still needs help
|
The new :mod:`multiprocessing` package lets Python programs create new
|
||||||
|
processes that will perform a computation and return a result to the
|
||||||
|
parent. The parent and child processes can communicate using queues
|
||||||
|
and pipes, synchronize their operations using locks and semaphores,
|
||||||
|
and can share simple arrays of data.
|
||||||
|
|
||||||
:mod:`multiprocessing` makes it easy to distribute work over multiple processes.
|
The :mod:`multiprocessing` module started out as an exact emulation of
|
||||||
Its API is similar to that of :mod:`threading`. For example::
|
the :mod:`threading` module using processes instead of threads. That
|
||||||
|
goal was discarded along the path to Python 2.6, but the general
|
||||||
|
approach of the module is still similar. The fundamental class
|
||||||
|
is the :class:`Process`, which is passed a callable object and
|
||||||
|
a collection of arguments. The :meth:`start` method
|
||||||
|
sets the callable running in a subprocess, after which you can call
|
||||||
|
the :meth:`is_alive` method to check whether the subprocess is still running
|
||||||
|
and the :meth:`join` method to wait for the process to exit.
|
||||||
|
|
||||||
from multiprocessing import Process
|
Here's a simple example where the subprocess will calculate a
|
||||||
|
factorial. The function doing the calculation is a bit strange; it's
|
||||||
|
written to take significantly longer when the input argument is a
|
||||||
|
multiple of 4.
|
||||||
|
|
||||||
def long_hard_task(n):
|
::
|
||||||
print n * 43
|
|
||||||
|
|
||||||
for i in range(10):
|
import time
|
||||||
Process(target=long_hard_task, args=(i)).start()
|
from multiprocessing import Process, Queue
|
||||||
|
|
||||||
will multiply the numbers between 0 and 10 times 43 and print out the result
|
|
||||||
concurrently.
|
def factorial(queue, N):
|
||||||
|
"Compute a factorial."
|
||||||
|
# If N is a multiple of 4, this function will take much longer.
|
||||||
|
if (N % 4) == 0:
|
||||||
|
time.sleep(.05 * N/4)
|
||||||
|
|
||||||
|
# Calculate the result
|
||||||
|
fact = 1L
|
||||||
|
for i in range(1, N+1):
|
||||||
|
fact = fact * i
|
||||||
|
|
||||||
|
# Put the result on the queue
|
||||||
|
queue.put(fact)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
queue = Queue()
|
||||||
|
|
||||||
|
N = 5
|
||||||
|
|
||||||
|
p = Process(target=factorial, args=(queue, N))
|
||||||
|
p.start()
|
||||||
|
p.join()
|
||||||
|
|
||||||
|
result = queue.get()
|
||||||
|
print 'Factorial', N, '=', result
|
||||||
|
|
||||||
|
A :class:`Queue` object is created and stored as a global. The child
|
||||||
|
process will use the value of the variable when the child was created;
|
||||||
|
because it's a :class:`Queue`, parent and child can use the object to
|
||||||
|
communicate. (If the parent were to change the value of the global
|
||||||
|
variable, the child's value would be unaffected, and vice versa.)
|
||||||
|
|
||||||
|
Two other classes, :class:`Pool` and :class:`Manager`, provide
|
||||||
|
higher-level interfaces. :class:`Pool` will create a fixed number of
|
||||||
|
worker processes, and requests can then be distributed to the workers
|
||||||
|
by calling :meth:`apply` or `apply_async`, adding a single request,
|
||||||
|
and :meth:`map` or :meth:`map_async` to distribute a number of
|
||||||
|
requests. The following code uses a :class:`Pool` to spread requests
|
||||||
|
across 5 worker processes, receiving a list of results back.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
from multiprocessing import Pool
|
||||||
|
|
||||||
|
p = Pool(5)
|
||||||
|
result = p.map(factorial, range(1, 1000, 10))
|
||||||
|
for v in result:
|
||||||
|
print v
|
||||||
|
|
||||||
|
This produces the following output::
|
||||||
|
|
||||||
|
1
|
||||||
|
39916800
|
||||||
|
51090942171709440000
|
||||||
|
8222838654177922817725562880000000
|
||||||
|
33452526613163807108170062053440751665152000000000
|
||||||
|
...
|
||||||
|
|
||||||
|
The :class:`Manager` class creates a separate server process that can
|
||||||
|
hold master copies of Python data structures. Other processes can
|
||||||
|
then access and modify these data structures by using proxy objects.
|
||||||
|
The following example creates a shared dictionary by calling the
|
||||||
|
:meth:`dict` method; the worker processes then insert values into the
|
||||||
|
dictionary. (No locking is done automatically, which doesn't matter
|
||||||
|
in this example. :class:`Manager`'s methods also include
|
||||||
|
:meth:`Lock`, :meth:`RLock`, and :meth:`Semaphore` to create shared locks.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
import time
|
||||||
|
from multiprocessing import Pool, Manager
|
||||||
|
|
||||||
|
def factorial(N, dictionary):
|
||||||
|
"Compute a factorial."
|
||||||
|
# Calculate the result
|
||||||
|
fact = 1L
|
||||||
|
for i in range(1, N+1):
|
||||||
|
fact = fact * i
|
||||||
|
|
||||||
|
# Store result in dictionary
|
||||||
|
dictionary[N] = fact
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
p = Pool(5)
|
||||||
|
mgr = Manager()
|
||||||
|
d = mgr.dict() # Create shared dictionary
|
||||||
|
|
||||||
|
# Run tasks using the pool
|
||||||
|
for N in range(1, 1000, 10):
|
||||||
|
p.apply_async(factorial, (N, d))
|
||||||
|
|
||||||
|
# Mark pool as closed -- no more tasks can be added.
|
||||||
|
p.close()
|
||||||
|
|
||||||
|
# Wait for tasks to exit
|
||||||
|
p.join()
|
||||||
|
|
||||||
|
# Output results
|
||||||
|
for k, v in sorted(d.items()):
|
||||||
|
print k, v
|
||||||
|
|
||||||
|
This will produce the output::
|
||||||
|
|
||||||
|
1 1
|
||||||
|
11 39916800
|
||||||
|
21 51090942171709440000
|
||||||
|
31 8222838654177922817725562880000000
|
||||||
|
41 33452526613163807108170062053440751665152000000000
|
||||||
|
51 1551118753287382280224243016469303211063259720016986112000000000000
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
|
The documentation for the :mod:`multiprocessing` module.
|
||||||
|
|
||||||
:pep:`371` - Addition of the multiprocessing package
|
:pep:`371` - Addition of the multiprocessing package
|
||||||
PEP written by Jesse Noller and Richard Oudkerk;
|
PEP written by Jesse Noller and Richard Oudkerk;
|
||||||
implemented by Richard Oudkerk and Jesse Noller.
|
implemented by Richard Oudkerk and Jesse Noller.
|
||||||
|
|
||||||
|
|
||||||
.. ======================================================================
|
.. ======================================================================
|
||||||
|
|
||||||
.. _pep-3101:
|
.. _pep-3101:
|
||||||
|
|
Loading…
Reference in New Issue