【问题标题】:parallel list comprehension using Pool map使用池映射的并行列表理解
【发布时间】:2015-08-03 04:05:20
【问题描述】:

我有一个列表理解:

thingie=[f(a,x,c) for x in some_list]

我将其并行化如下:

from multiprocessing import Pool

pool=Pool(processes=4)

thingie=pool.map(lambda x: f(a,x,c), some_list)

但我收到以下错误:

_pickle.PicklingError: Can't pickle <function <lambda> at 0x7f60b3b0e9d8>:
attribute lookup <lambda> on __main__ failed

我尝试安装 pathos 包,它显然解决了这个问题,但是当我尝试导入它时,我得到了错误:

ImportError: No module named 'pathos'

【问题讨论】:

  • 你为什么不直接使用 thingie=pool.map(f, some_list) ?检查是否可行,我可能有一个想法。
  • 嗯,a 和 c 是单独定义的,需要传递给函数,所以我最终会出错。
  • 我的想法是 lambda 是不可提取的,因为您无法获得源代码,因此无法将其发送到另一个进程中执行。尝试创建包装函数,例如 def wrap_f(x): return f(a, x, c) 并将其传递给 pool.map
  • 成功了!谢谢!
  • 我是pathos 作者。 pathos几乎兼容 python 3.x……但还没有。所以这就是它对你不起作用的原因——它无法安装。 pathos 可以序列化lambda 的原因是它使用dill 序列化程序,它知道如何序列化lambdadill 通过序列化lambda 的代码来序列化lambda(基本上)。

标签: python-3.4 python-multiprocessing pathos


【解决方案1】:

好的,所以这个答案只是为了记录,我已经在评论对话中与问题的作者弄清楚了。

multiprocessing 需要在进程之间传输每个对象,因此它使用pickle 在一个进程中序列化它并在另一个进程中反序列化。一切正常,但pickle 无法序列化lambda。 AFAIR 之所以如此,是因为pickle 需要函数源来序列化它,而lambda 不会拥有它,但我不能 100% 确定,也不能引用我的源。

如果您在 1 个参数函数上使用 map() 不会有任何问题 - 您可以传递该函数而不是 lambda。如果您有更多参数,例如在您的示例中,则需要使用 def 关键字定义一些包装器:

from multiprocessing import Pool

def f(x, y, z):
    print(x, y, z)

def f_wrapper(y):
    return f(1, y, "a")

pool = Pool(processes=4)

result = pool.map(f_wrapper, [7, 9, 11])

【讨论】:

    【解决方案2】:

    就在我关闭它之前,我找到了另一种使用 Python 3 执行此操作的方法,使用 functools,

    假设我有一个函数f,其中包含三个变量f(a,x,c),我想要其中一个变量,比如x。我可以使用以下代码基本上完成@FilipMalczak 建议的操作:

    import functools
    from multiprocessing import Pool
    
    
    f1=functools.partial(f,a=10)
    
    f2=functools.partial(f2,c=10)
    
    pool=Pool(processes=4)
    final_answer=pool.map(f2,some_list)
    

    【讨论】:

    • 整洁,坦率地说 - 比我的想法更好。不过,我的回答说明了问题的原因。
    猜你喜欢
    • 2017-05-10
    • 2017-01-20
    • 2020-09-29
    • 2010-11-21
    • 1970-01-01
    • 1970-01-01
    • 2011-02-11
    • 2018-05-05
    • 2011-02-28
    相关资源
    最近更新 更多