【问题标题】:Python Multiprocessing Slower and not really working for object methodsPython 多处理速度较慢且不适用于对象方法
【发布时间】:2018-05-11 14:27:39
【问题描述】:

编辑:运行 Apple MBP 2017 Model 14,3,2.8GHz i7 4 核:

multiprocessing.cpu_count()
8

我有一个对象列表,我在 python 中为每个对象执行一次对象方法。该过程适用于遗传算法,因此我有兴趣加快它的速度。基本上,每次我使用数据列表中的数据更新环境时,对象(基因组)都会执行一些数学运算,包括从环境中获取值,并引用它自己的内部值。
我在做:

from multiprocessing import Pool

class Individual(object):
    def __init__(self):
    self.parameter1 = None
    self.parameter2 = None

    def update_values():
        # reads the environment variables, does math specific to each instance
        # updates internal parameters
        a, b, c, d = environment_variables
        self.parameter1 = do_math(a, b, c, d, 
                                  self.parameter1, self.parameter2)
        self.parameter2 = do_math(a, b, c, d, 
                                  self.parameter1, self.parameter2) 


data_list = [data1, data2, data3, ..., data1000]
object_list = [object1, object2, object3, ..., object20000]

如果我运行这个:

for newdataset in data_list:
    update_parameters(newdataset)
    for object in object_list:
        object.update_values()

这比我尝试使用 multiprocessing/map 拆分它快 很多

def process_object(object):
    object.update_values()

for newdataset in data_list:
    update_parameters(newdataset)
    with Pool(4) as p:
        p.map(process_object, object_list)

如果我以 200(而不是 20000)的 object_list 长度运行,则在单线程模式下总时间为 14.8 秒。 如果我在多处理模式下运行相同的总时间......仍在等待......好的...... 211秒。
此外,它似乎根本没有按照函数所说的那样做。我在这里想念什么?当我检查每个对象的值时,它们似乎根本没有更新。

【问题讨论】:

  • 您能否详细说明正在进行的处理方式?另外,你有多少个核心?什么操作系统?
  • 此外,传递给进程的所有参数都必须是可序列化的。那么,object_list 中有哪些对象(类实例默认不是serialize-ale)?
  • multiprocessing 使用pickle 来序列化数据,并且可以处理类以及递归结构。
  • 哇,谢谢大家。我将再次编辑我的问题以使其更清楚。

标签: python python-3.x multiprocessing


【解决方案1】:

我会稍微不同地拆分并行化。很难说update_parameters 发生了什么,但我也会并行调用它。为什么要把它放在外面?您可以将您感兴趣的整个操作封装在某个函数中,对吧?

另外,这很重要:您需要确保只有在主进程中才打开池。所以添加行

if __name__ == '__main__':
     with Pool(multiprocessing.cpu_count()) as p:

【讨论】:

  • 很抱歉在您发表评论后我完成更新之前您回答了。我没有在 main 函数中执行 Pool,但我没有从 windows 运行,所以应该没问题吧?
  • @Notachance 在这种情况下,问题与您的程序逻辑和您正在调用的函数的内容有关 - 如果您能提供更多详细信息,我可以为您提供帮助。跨度>
  • 另外这篇 SO 帖子可能会有所帮助 - stackoverflow.com/questions/26911882/… 如果可以的话,您可以让每个进程从一个单独的文件中读取它应该处理的数据,这会比您的主进程更快读取所有内容,然后通过 IPC 将数据分发给其子代。
【解决方案2】:

当您使用多处理时,您会以两种方式对数据进行序列化和传输。在这种情况下,这包括您打算调用 update_values 的每个对象。我猜你也在迭代你的模型,这意味着它们会被来回发送很多次。此外,map() 返回结果列表,但 process_object 只返回 None。因此,您已经序列化了一个模型,将其发送到另一个进程,让该进程运行并更新模型,然后返回 None 并丢弃更新的模型,然后丢弃 None 结果列表。如果您要退回模型:

def process_object(object):
    object.update_values()
    return object

...

object_list = p.map(process_object, object_list)

您的程序实际上可能会产生一些结果,但几乎可以肯定仍然比您希望的要慢。特别是您的进程池将没有 data_list 或类似的东西(“环境”?) - 它只接收您通过 Pool.map() 传递的内容。

您可能需要考虑使用其他工具,例如 tensorflow 或 MPI。至少阅读sharing state between processes。此外,您可能不应该为每次迭代都重新创建进程池。这在某些平台上非常昂贵,例如 Windows。

【讨论】:

  • 我希望更新列表中的参数,而不是返回它们的副本。没有意识到多处理正在腌制一切。嗯
  • 谢谢。我没有意识到我是在“进程之间共享”,因为我的对象根本没有相互交谈。我会尝试几件事,然后再回来。
猜你喜欢
  • 2019-09-01
  • 2019-12-05
  • 1970-01-01
  • 1970-01-01
  • 2014-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多