views:

1370

answers:

1

Hi,

I'm trying to use multiprocessing's Pool.map() function to divide out work simultaneously. When I use the following code, it works fine:

import multiprocessing

def f(x):
    return x*x

def go():
    pool = multiprocessing.Pool(processes=4)             
    #result = pool.apply_async(self.f, [10])     
    #print result.get(timeout=1)           
    print pool.map(f, range(10))


if __name__== '__main__' :
    go()

However, when I use it in a more object-oriented approach, it doesn't work. The error message it gives is:

PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup
__builtin__.instancemethod failed

This occurs when the following is my main program:

import someClass

if __name__== '__main__' :
    # lfq = lastFmQueries.lastFmQueries()
    # x = lfq.getUsersTopTracks("acet", "overall")
    sc = someClass.someClass()
    sc.go()

and the following is my someClass class:

import multiprocessing

class someClass(object):
    def __init__(self):
        pass

    def f(self, x):
        return x*x

    def go(self):
        pool = multiprocessing.Pool(processes=4)             
        #result = pool.apply_async(self.f, [10])     
        #print result.get(timeout=1)           
        print pool.map(self.f, range(10))

Anyone know what the problem could be, or an easy way around it?

+10  A: 

The problem is that multiprocessing must pickle things to sling them among processes, and bound methods are not picklable. The workaround (whether you consider it "easy" or not;-) is to add the infrastructure to your program to allow such methods to be pickled, registering it with the copy_reg standard library method.

For example, Steven Bethard's contribution to this thread (towards the end of the thread) shows one perfectly workable approach to allow method pickling/unpickling via copy_reg.

Alex Martelli
That's great - thank you. Seem to have progressed some way, anyhow: Using the code at http://pastebin.ca/1693348 I now get a RuntimeError: maximum recursion depth exceeded. I looked around and one forum post recommended increasing the maximum depth to 1500 (from the default 1000) but I had no joy there. To be honest, I can't see what part (of my code, at least) could be recursing out of control, unless for some reason the code is pickling and unpickling in a loop, due to slight changes I made in order to make Steven's code OO'd?
ventolin
Your `_pickle_method` returns `self._unpickle_method`, a bound method; so of course pickle now tries to pickle THAT -- and it does as you've told it to: by calling `_pickle_method`, recursively. I.e. by `OO`ing the code in this way, you have inevitably introduced infinite recursion. I suggest going back to Steven's code (and not worshipping at the altar of OO when not appropriate: many things in Python are best done in a more functional-way, and this is one).
Alex Martelli