【问题标题】:How can I use python multiprocessing with generators?如何将 python 多处理与生成器一起使用?
【发布时间】:2020-07-03 06:04:41
【问题描述】:

我想在 python 中使用带有生成器函数的多处理

假设我有大量列表big_list,我想使用多处理来计算值。如果我使用返回值的“传统”函数,这很简单:

import concurrent

def compute_function(list_of_lists):
    return_values = []   ## empty list
    for list in list_of_lists:
        new_value = compute_something(list)    ## compute something; just an example
        return_values.append(new_value)  ## append to list
    return return_values

with concurrent.futures.ProcessPoolExecutor(max_workers=N) as executor:
        new_list = list(executor.map(compute_function, big_list))

但是,以这种方式使用列表会占用大量内存。所以我想改用生成器函数:

import concurrent

def generator_function(list_of_lists):
    for list in list_of_lists:
        new_value = compute_something(list)    ## compute something; just an example
        yield new_value

with concurrent.futures.ProcessPoolExecutor(max_workers=N) as executor:
        new_list = list(executor.map(generator_function, big_list))

我的问题是,你不能腌制生成器。对于其他数据结构,有一些解决此问题的方法,但我认为不适用于生成器。

我怎样才能做到这一点?

【问题讨论】:

  • 您能否为此提供更多背景信息?可能有更好的方法来提高性能。
  • @AMC 我试图避免使用大型列表,因为它们无法放入内存。有关更多上下文,我在这里有一个类似的问题:stackoverflow.com/questions/60798407/…
  • @AMC 我会说,我正在处理的基本问题是如何使用多处理而不是在 RAM 中爆炸。这本质上是我的问题,而我目前拥有的数据结构是一个列表字典——这有意义吗?
  • 如果在生成结果时循环遍历结果,是否仍会占用大量内存?您是否稍后以减少内存消耗的方式转换结果,程序的其余部分是否设置为这样工作?
  • "如果在结果生成时循环遍历结果,是否仍然太占用内存?"这不会比使用多处理慢得多吗?

标签: python parallel-processing multiprocessing bigdata generator


【解决方案1】:

您可以使用itertools.chain.from_iterablebig_list 中更深一层地进行枚举以迭代子列表。

import concurrent
import itertools

def compute_function(item):
    return compute_something(item)

with concurrent.futures.ProcessPoolExecutor(max_workers=N) as executor:
    for result in executor.map(compute_function,
            itertools.chain.from_iterable(big_list)):
        print(result)

【讨论】:

  • 我怀疑这会像第一种方法一样占用大量内存,并且不会解决我的问题。
【解决方案2】:

generator 只是一个保存状态的奇特循环,它类似于迭代器逻辑,它为您提供nexthasNext 和类似的 api,因此您的循环将询问该迭代器的下一项(如只要它有下一项)

生成器的植入完全取决于开发者,可以通过

  • 将所有数据加载到内存并用next遍历,从而达到无内存效率,例如for i in [1,2,3,4]
  • 逐行读取某个文件,例如for line in file
  • 如果生成函数已知,则根据最后生成的元素生成下一个元素,例如range(100)
  • 还有更多...

都有一个共同的要求,生成器需要保持它的当前状态,以便它知道在下一个状态下yield 是什么,从而使它非常有状态,这反过来又使它在多处理中使用非常糟糕的选择...

您可以使用 map-reduce 类似的逻辑来解决这个问题,并将整个列表拆分为小的子列表,将它们传递给工作人员并将其所有输出连接到最终结果

【讨论】:

  • "generator 只是一个保存状态的奇特循环,因此使其非常有状态,这反过来又使它在多处理中使用是非常糟糕的选择......" 我不明白这个---你能再解释一下吗?
  • 编辑我的答案,您能否提供有关您的用例的更多详细信息,以便我也可以为您的问题提供解决方案...
  • 感谢您的帮助---我已尝试在此处更好地解释问题:stackoverflow.com/questions/60811456/…
  • @EB2127,仍然没有足够的处理逻辑信息,以及那些list of lists是否独立,我的建议仍然是,尝试使用一些map-reduce接近
  • 我同意---问题是,如何以可扩展的方式做到这一点,这也不会爆炸内存
猜你喜欢
  • 2023-02-16
  • 2021-06-25
  • 1970-01-01
  • 2019-12-15
  • 2018-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-22
相关资源
最近更新 更多