【发布时间】:2020-11-23 20:21:10
【问题描述】:
我看到了一些建议,我什至不应该使用多处理来执行此操作,或者这不是使用多处理(内存共享)的方式,但我还是要问一下,看看我是否能更好地理解它。
我有一个 Person 类,我想使用 update_age 方法更新那个人的年龄。假设我有数百万个 Person 对象(而不是这里显示的 4 个),我想使用 Multiprocessing 来更新我拥有的所有 Person 实例的年龄。
class Person():
def __init__(self, age):
self.age = age
def update_age(self):
self.age += 10
people = [Person(1), Person(2), Person(3), Person(4)]
p = Pool(4)
results = [p.apply_async(person.update_age, ()) for person in people]
print([res.get() for res in results])
这会给我[None, None, None, None],因为方法 Person.update_age 没有返回任何东西。如果我将课程更改为:
class Person():
def __init__(self, age):
self.age = age
def update_age(self):
return self.age + 10
我会得到正确的回复[11, 12, 13, 14]。但这需要我重构该类中的所有方法。如果我在不考虑可伸缩性的情况下开发 Person 类,那就需要做很多工作。
有什么方法可以让我保持课程的原始结构,并且仍然能够使用多处理将工作负载分散到我的所有 CPU 上?
编辑:所以如果我在父进程中有这样的方法。
def update_all():
for person in people:
person.update_age()
使用所有 CPU 更新所有“人”的正确方法是什么?
【问题讨论】:
-
您可以尝试使用多线程
map()而不是多处理。见concurrent.futures.Executor#map -
需要明确的是,这对
multiprocessing没有意义。您派生或派生工作进程的实例,它们的对象不再连接到父进程的对象。因此,就地更新Person实例只会更改工作端的副本,而不是父端。使用来自multiprocessing的共享类型让你的整个班级意识到多处理可以使这项工作有效,但这是一个糟糕的主意。最好的解决方案是纯功能解决方案;传入实例,接收新实例以替换它们,不要改变现有实例。 -
@ShadowRanger 我喜欢你的建议,这正是我所期待的。但让我改写一下。你是说如果我想使用多个CPU核心,我应该用params和return编写所有函数吗?这是否意味着我根本不能在那些地方使用 OOP?我无法避免这里的重构?
-
@yangliu2:基本上,是的。就像我说的那样,旨在通过共享内存(或代理)跨进程共享数据的类在理论上可以工作,但它既丑陋又毫无意义(你会在 IPC 上花费这么多时间,你不妨在父进程中运行它过程)。
-
@ShadowRanger 感谢您的回复。我最后更新了我原来的问题,请让我知道在父进程中正确的方法是什么。谢谢!
标签: python oop multiprocessing