为什么pool.map()和map()会返回不同的结果?

时间:2016-08-06 18:19:57

标签: python group-by multiprocessing itertools pool

我有以下程序:

import string
import itertools
import multiprocessing as mp

def test(word_list):
    return list(map(lambda xy: (xy[0], len(list(xy[1]))),
        itertools.groupby(sorted(word_list))))

def f(x):
    return (x[0], len(list(x[1])))

def test_parallel(word_list):
    w = mp.cpu_count()
    pool = mp.Pool(w)
    return (pool.map(f, itertools.groupby(sorted(word_list))))

def main():
    test_list = ["test", "test", "test", "this", "this", "that"]

    print(test(test_list))
    print(test_parallel(test_list))

    return

if __name__ == "__main__":
    main()

输出结果为:

[('test', 3), ('that', 1), ('this', 2)]
[('test', 0), ('that', 0), ('this', 1)]

第一行是预期的正确结果。我的问题是,为什么pool.map()没有返回与map()相同的结果?

另外,我知道6项列表不是多处理的最佳选择。这只是我在更大的应用程序中实现时遇到的问题的演示。

我正在使用Python 3.5.1。

2 个答案:

答案 0 :(得分:3)

来自https://docs.python.org/3.5/library/itertools.html#itertools.groupby

  

返回的组本身就是一个共享底层的迭代器   可以使用groupby()进行迭代。因为源是共享的,所以   groupby()对象是高级的,前一个组不再可见。   因此,如果以后需要该数据,则应将其存储为列表:

groups = []
uniquekeys = []
data = sorted(data, key=keyfunc)
for k, g in groupby(data, keyfunc):
    groups.append(list(g))      # Store group iterator as a list
    uniquekeys.append(k)

我认为这里的问题是Pool.map试图切断其输入,并且这样做会迭代groupby的结果,这会有效地跳过除最后一个之外的所有元素。基。

您的代码的一个修复方法是使用类似[(k, list(v)) for k, v in itertools.groupby(sorted(word_list))]的内容,但我不知道这对您的实际用例有多适用。

答案 1 :(得分:2)

groupby()每组返回 iterators ,这些不是独立的来自传入的底层迭代器。您无法独立迭代这些组在平行下;当你访问下一组时,任何前面的组都会提前结束。

pool.map()将尝试读取所有groupby()迭代器结果,以将这些结果发送到单独的函数;只是试图获得第二组将导致第一组为空。

只需通过迭代pool.map()的下一个结果,您就可以在没有groupby()的情况下看到相同的结果:

>>> from itertools import groupby
>>> word_list = ["test", "test", "test", "this", "this", "that"]
>>> iterator = groupby(sorted(word_list))
>>> first = next(iterator)
>>> next(first[1])
'test'
>>> second = next(iterator)
>>> list(first[1])
[]

第一组的剩余部分是空的'因为已经要求第二组。

这显然是documented

  

由于源是共享的,因此当groupby()对象提前时,前一个组将不再可见。

你必须实现' 之前将每个组发送到函数:

return pool.map(lambda kg: f((k[0], list(kg[1]))), itertools.groupby(sorted(word_list)))

return pool.map(f, (
    (key, list(group)) for key, group in itertools.groupby(sorted(word_list))))

其中生成器表达式将实现作为pool.map()迭代进行处理。