如何让Pool.map接受lambda函数

80

我有以下函数:

def copy_file(source_file, target_dir):
    pass

现在我想使用multiprocessing同时执行这个函数:

p = Pool(12)
p.map(lambda x: copy_file(x,target_dir), file_list)

问题是,lambda函数无法被 pickled,所以会失败。如何以最简洁(Pythonic)的方式解决这个问题?

5个回答

77

使用函数对象:

class Copier(object):
    def __init__(self, tgtdir):
        self.target_dir = tgtdir
    def __call__(self, src):
        copy_file(src, self.target_dir)

要运行你的 Pool.map

p.map(Copier(target_dir), file_list)

1
如果copy_file是一个方法中的self.copy_file呢? - Константин Ван

70

1
这个看起来甚至更干净... 我稍后会决定哪一个成为我的答案。 - Peter Smit
@Peter Smit:糟糕——你在我删除帖子之前看到了它……我重新发布这个帖子只是为了宣布由于Python2中的一个错误,它无法工作。 - unutbu
1
不过,这个答案还是加一分,因为它更短(在Python 3中)。 - Fred Foo
9
补充一下,functools.partial 在 Python 2.7 中也可进行 pickle 序列化。 - pythonic metaphor
1
使用这个方法来修复非同构图的并行搜索。它比Fred Foo的解决方案快15倍。 - Alice Schwarze
显示剩余2条评论

11

问题有点旧了,但是如果你仍在使用Python 2,我的答案可能会有用。

关键是使用 pathos 项目的一部分:multiprocess,它是 multiprocessing 的分支版本。它摆脱了原始 multiprocess 的烦人限制。

安装:pip install multiprocess

用法:

>>> from multiprocess import Pool
>>> p = Pool(4)
>>> print p.map(lambda x: (lambda y:y**2)(x) + x, xrange(10))
[0, 2, 6, 12, 20, 30, 42, 56, 72, 90]

1

你可以使用starmap()和池化来解决这个问题。

假设你有一个文件列表,比如在你的工作目录中,你想要将这些文件复制到一个位置,那么你可以import os并使用os.system()在Python中运行终端命令。这将使您轻松地移动文件。

但是,在开始之前,您需要创建一个变量res = [(file, target_dir) for file in file_list],它将存储每个文件与目标目录。

它看起来像...

[('test1.pdf', '/home/mcurie/files/pdfs/'), ('test2.pdf', '/home/mcurie/files/pdfs/'), ('test3.pdf', '/home/mcurie/files/pdfs/'), ('test4.pdf', '/home/mcurie/files/pdfs/')]

显然,对于这种用例,您可以通过将每个文件和目标目录存储在一个字符串中来简化此过程,但这将降低使用此方法的洞察力。

思路是starmap()将接受res的每个组件并将其放入函数copy_file(source_file, target_dir)中并同步执行它们(这受限于您CPU的核心数量)。

因此,第一个操作线程将如下所示

copy_file('test1.pdf', '/home/mcurie/files/pdfs/')

希望这可以帮助您。完整代码如下。

from multiprocessing.pool import Pool
import os

file_list = ["test1.pdf", "test2.pdf", "test3.pdf", "test4.pdf"]
target_dir = "/home/mcurie/files/pdfs/"


def copy_file(source_file, target_dir):
    os.system(f"cp {source_file} {target_dir + source_file}")
    
if __name__ == '__main__':
    with Pool() as p:
        res = [(file, target_dir) for file in file_list]
        for results in p.starmap(copy_file, res):
            pass

1

this的答案中可以看出,pathos让你可以直接运行lambda表达式p.map(lambda x: copy_file(x,target_dir), file_list),省去了所有的解决方法/黑客工具。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接