Multiprocessing, shared memory vs. pickled copies
Robert Kern
robert.kern at gmail.com
Mon Apr 4 20:05:35 EDT 2011
On 4/4/11 3:20 PM, John Ladasky wrote:
> Hi folks,
>
> I'm developing some custom neural network code. I'm using Python 2.6,
> Numpy 1.5, and Ubuntu Linux 10.10. I have an AMD 1090T six-core CPU,
> and I want to take full advantage of it. I love to hear my CPU fan
> running, and watch my results come back faster.
You will want to ask numpy questions on the numpy mailing list.
http://www.scipy.org/Mailing_Lists
> When I'm training a neural network, I pass two numpy.ndarray objects
> to a function called evaluate. One array contains the weights for the
> neural network, and the other array contains the input data. The
> evaluate function returns an array of output data.
>
> I have been playing with multiprocessing for a while now, and I have
> some familiarity with Pool. Apparently, arguments passed to a Pool
> subprocess must be able to be pickled. Pickling is still a pretty
> vague progress to me, but I can see that you have to write custom
> __reduce__ and __setstate__ methods for your objects. An example of
> code which creates a pickle-friendly ndarray subclass is here:
>
> http://www.mail-archive.com/numpy-discussion@scipy.org/msg02446.html
Note that numpy arrays are already pickle-friendly. This message is telling you
how, *if* you are already subclassing, how to make your subclass pickle the
extra information it holds.
> Now, I don't know that I actually HAVE to pass my neural network and
> input data as copies -- they're both READ-ONLY objects for the
> duration of an evaluate function (which can go on for quite a while).
> So, I have also started to investigate shared-memory approaches. I
> don't know how a shared-memory object is referenced by a subprocess
> yet, but presumably you pass a reference to the object, rather than
> the whole object. Also, it appears that subprocesses also acquire a
> temporary lock over a shared memory object, and thus one process may
> well spend time waiting for another (individual CPU caches may
> sidestep this problem?) Anyway, an implementation of a shared-memory
> ndarray is here:
>
> https://bitbucket.org/cleemesser/numpy-sharedmem/src/3fa526d11578/shmarray.py
>
> I've added a few lines to this code which allows subclassing the
> shared memory array, which I need (because my neural net objects are
> more than just the array, they also contain meta-data).
Honestly, you should avoid subclassing ndarray just to add metadata. It never
works well. Make a plain class, and keep the arrays as attributes.
> But I've run
> into some trouble doing the actual sharing part. The shmarray class
> CANNOT be pickled.
Please never just *say* that something doesn't work. Show us what you tried, and
show us exactly what output you got. I assume you tried something like this:
[Downloads]$ cat runmp.py
from multiprocessing import Pool
import shmarray
def f(z):
return z.sum()
y = shmarray.zeros(10)
z = shmarray.ones(10)
p = Pool(2)
print p.map(f, [y, z])
And got output like this:
[Downloads]$ python runmp.py
Exception in thread Thread-2:
Traceback (most recent call last):
File
"/Library/Frameworks/Python.framework/Versions/7.0/lib/python2.7/threading.py",
line 530, in __bootstrap_inner
self.run()
File
"/Library/Frameworks/Python.framework/Versions/7.0/lib/python2.7/threading.py",
line 483, in run
self.__target(*self.__args, **self.__kwargs)
File
"/Library/Frameworks/Python.framework/Versions/7.0/lib/python2.7/multiprocessing/pool.py",
line 287, in _handle_tasks
put(task)
PicklingError: Can't pickle <class
'multiprocessing.sharedctypes.c_double_Array_10'>: attribute lookup
multiprocessing.sharedctypes.c_double_Array_10 failed
Now, the sharedctypes is supposed to implement shared arrays. Underneath, they
have some dynamically created types like this c_double_Array_10 type.
multiprocessing has a custom pickler which has a registry of reduction functions
for types that do not implement a __reduce_ex__() method. For these dynamically
created types that cannot be imported from a module, this dynamic registry is
the only way to do it. At least at one point, the Connection objects which
communicate between processes would use this custom pickler to serialize objects
to bytes to transmit them.
However, at least in Python 2.7, multiprocessing seems to have a C extension
module defining the Connection objects. Unfortunately, it looks like this C
extension just imports the regular pickler that is not aware of these custom
types. That's why you get this error. I believe this is a bug in Python.
So what did you try, and what output did you get? What version of Python are you
using?
> I think that my understanding of multiprocessing
> needs to evolve beyond the use of Pool, but I'm not sure yet. This
> post suggests as much.
>
> http://mail.scipy.org/pipermail/scipy-user/2009-February/019696.html
Maybe. If the __reduce_ex__() method is implemented properly (and
multiprocessing bugs aren't getting in the way), you ought to be able to pass
them to a Pool just fine. You just need to make sure that the shared arrays are
allocated before the Pool is started. And this only works on UNIX machines. The
shared memory objects that shmarray uses can only be inherited. I believe that's
what Sturla was getting at.
--
Robert Kern
"I have come to believe that the whole world is an enigma, a harmless enigma
that is made terrible by our own mad attempt to interpret it as though it had
an underlying truth."
-- Umberto Eco
More information about the Python-list
mailing list