I recently saw a answer/comment about how functions are objects in python. So, I wondering why when I take that example, and create a class around it while initializing a variable, it doesn't work the same way. (The class example receives a pickling error):
PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed
Does anyone know why this is?
Example code from the link:
import multiprocessing as mp
def f(x):
f.q.put('Doing: ' + str(x))
return x*x
def f_init(q):
f.q = q
def main():
jobs = range(1,6)
q = mp.Queue()
p = mp.Pool(None, f_init, [q])
results = p.imap(f, jobs)
p.close()
for i in range(len(jobs)):
print q.get()
print results.next()
if __name__ == '__main__':
main()
Same example while puttin f
into a class:
import multiprocessing as mp
class F:
def __init__(self, q):
self.q = q
def f(x):
self.q.put('Doing: ' + str(x))
return x*x
def main():
jobs = range(1,6)
q = mp.Queue()
p = mp.Pool(None)
f = F(q)
results = p.imap(f.f, jobs)
p.close()
for i in range(len(jobs)):
print q.get()
print results.next()
if __name__ == '__main__':
main()
Instance methods are not automatically picklable. So
fails because
p.imap
tries to pickle the arguments. There is a way to "teach" pickle how to pickle instance methods (see Steven Bethard's answer), but your code has another problem: Passing the queue to the instance leads to a RuntimeError:The error message is a little confusing (at least to me) since you can pass the queue as an argument to
p.imap
, but you can not pass it to the classF
first, and then transfer it to the worker processes throughf.f
.Anyway, because of these problems, I'd suggest sticking with the original code instead of trying to wrap the code in a class.
Here is an example of how to pickle instance methods:
yields