多处理时保留类实例列表内容

时间:2013-05-05 23:12:33

标签: python multiprocessing

假设我有一些名为dog的课程:

class dog():
     def __init__(self, name, age):
          self.name = name
          self.age = age
          self.fleas = []

现在让我说我有一个名单,

names = ["bob", "joe", "dave"] 

我创建了一个列表,执行以下操作:

dogs = [dog(name, index) for index, name in enumerate(names)]  # Creates a list "dogs" that has 3 dog classes in it, named bob, joe, david, with ages 0, 1, 2 respectively.

现在我有一本跳蚤字典,

global_fleas = {"bob":[flea_43], "joe":[flea_20], "dave":[flea_3]}

并且有一些单独的方法flea_mod()修改此词典,以便将每只狗的跳蚤号码更改为某个随机数,例如flea_50。在这本词典中,每只狗只会有一只跳蚤。

我可以通过执行以下操作将global_fleas中的跳蚤附加到相应的狗:

def dirty_dog(dog):
     dog.fleas.append(global_fleas[dog.name])

这是踢球者。我想多处理这个循环。这就是我现在所拥有的:

while True:
    flea_mod()  # This randomizes the flea_number for each dog in the global_flea dictionary
    pool = multiprocessing.Pool(processes=len(dogs))
    [pool.apply_async(dirty_dog, dog) for dog in dogs]
    pool.close()
    pool.join()

所以问题是每次狗对象在每次循环运行时都不会保留其跳蚤列表。我希望每只狗的跳蚤清单在每个循环结束时保留,所以在两个循环后,每只狗将有两只跳蚤,依此类推。有任何想法吗?我猜我不得不腌制一些东西。

3 个答案:

答案 0 :(得分:1)

多处理文档尽可能建议不要使用共享状态,但您可以使用托管字典来实现目标:

http://docs.python.org/2/library/multiprocessing.html#sharing-state-between-processes

(请参阅基于服务器的管理器部分。)

这样,您可以根据核心逻辑更改单个托管对象,处理节点将看到更新的版本。您必须在代码中尝试一下才能看到最佳的共享设置(如果有的话)。

答案 1 :(得分:0)

J.F塞巴斯蒂安是对的。你没有在循环中看到突变的原因是它们发生在另一个过程中。你似乎对流程不是很熟悉;你应该考虑learning more about them

您想从泳池中取出结果,然后将它们复制到当地的狗身上。一种方法是修改你的循环,看起来像这样:

pool = multiprocessing.Pool(processes=some_number_of_processes)
while True:
    flea_mod()
    results = [pool.appy_async(dirty_dog, dog) for dog in dogs]
    for result, dog in zip(results, dogs):
        # I assume that dirty_dog returns the updated dog.
        dog.update(result.get(timeout=some_positive_number_of_seconds))

有几点需要注意:

  1. 您应避免在每次迭代期间创建新池。这样可以避免创建进程(池)的开销。
  2. some_number_of_processes可以是< len(dogs)!每个过程都会产生一些开销因此,有一个收益递减点。通常情况下,高估一点而非低估则更好。但是,除非你真的很懒,否则很容易避免过高估计。
  3. 如果您使用的是Python 3.2或更高版本,并且dirty_dog不受CPU限制(例如经常触摸磁盘),那么请考虑使用ThreadPoolExecutor;这样,不需要复制修改,因为线程将在相同的对象上操作,而不是复制。

答案 2 :(得分:0)

除非dirty_dog()执行一些未在此处显示的冗长计算;多处理不会提高性能(通过来回复制数据可以获得所有好处)。

import multiprocessing as mp

def dirty_dog(i):
    dog = dogs[i]
    dog.fleas.append(global_fleas[dog.name])
    dogs[i] = dog

def init(global_fleas_, dogs_):
    global global_fleas, dogs
    global_fleas, dogs = global_fleas_, dogs_

if __name__=="__main__":
    manager = mp.Manager()
    dogs = manager.list(dogs)
    pool = mp.Pool(initializer=init, initargs=[global_fleas, dogs])
    for _ in range(3):
       flea_mod()
       pool.map(dirty_dog, range(len(dogs)))
    pool.close()
    pool.join()