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

Pythonのmultiprocessingがタイトルのようにエラーを吐くことがある。
結論としてはmultiprocessingのPoolオブジェクトのメソッドをlambda式を引数、または返り値に取る関数を渡すと死ぬ。
具体的には以下。

#ダメパターン
import multiprocessing

f = lambda x: x* x
l = range(0, 10)

if __name__ = '__main__':
  p = multiprocessing.Pool(4)
  
  #実態はlambdaなので死ぬ。
  for i in p.imap(f, l):
       print i


#大丈夫なパターン
#普通の関数定義で呼び出してるのでOK
#hogeの中でlambdaは使ってるけど、returnしてるのはあくまでも
#lambdaの実効値なので関係が無い。

import multiprocessing

def  hoge(x):
   f = lambda x: x* x
   return f(x) + 2

l = range(0, 10)

if __name__ = '__main__':
  p = multiprocessing.Pool(4)
  for i in p.imap(hoge, l):
        print i


何でlambdaが渡せないのか


よく分からないが、pickleというモジュールをmultiprocessing内で使ってるっぽい。多分evalっぽいことをしていると思う。
そんな感じlambdaとかが渡せないんだろうな〜という感じ。
以下、iPythonの例

In[0]import pickle

In[0]: def hoge(y): return y* y

In[0]:pickle.dumps(hoge(2))
Out[35]: 'I4\n.'

In[0]:pickle.dumps(lambda: True)
---------------------------------------------------------------------------
PicklingError                             Traceback (most recent call last)

以上のようにlambdaをpickleに渡すと死ぬ。


multiprocessingで今回のようなエラーが出たら、multiproccessingのインスタンスで呼んでいる引数とか返り値がlambdaを含むオブジェクトとかで返してないか疑うべきではある。


参考資料


Pool.imap()について - Kesin's diary
http://kesin.hatenablog.com/entry/20111228/1325076388
Parallelism and Serialization
http://matthewrocklin.com/blog/work/2013/12/05/Parallelism-and-Serialization/


結構このエラーはあるあるらしい。StackOverflowとかで腐るほど見つかった。