multiprocessing模块与pyro的比较?
我在一个计算集群上使用 pyro 来管理并行任务。最近我换到了一个新的集群,在这里我需要负责使用每个计算节点上的所有核心。(在之前的集群中,每个核心都是一个独立的节点。)我觉得 Python 的 multiprocessing 模块很适合这个需求。我注意到它也可以用于 远程进程通信。如果有人同时使用过这两个框架进行远程进程通信,我很想知道它们之间的比较。multiprocessing 模块的一个明显优点是从 2.6 版本开始就已经内置了。除此之外,我很难判断哪个更好。
1 个回答
编辑:我在这里修改我的回答,希望能让你们少受点苦。多进程(multiprocessing)还不够成熟,BaseManager的文档是错误的,如果你是一个喜欢面向对象编程的人,想要在运行时动态创建共享对象,请使用PYRO,否则你会非常后悔! 如果你只是想用共享队列做一些功能性编程,像那些愚蠢的例子那样提前注册,那就祝你好运。
简短回答
多进程:
- 做面向对象的远程对象感觉很别扭
- 加密(authkey)很简单
- 可以在网络上或进程间通信
- 没有像Pyro那样的额外麻烦的名字服务器(不过有方法可以绕过这个)
- 编辑:一旦管理器实例化后,不能“注册”对象!!?
- 编辑:如果服务器没有启动,客户端会抛出“无效参数”的异常,而不是简单地说“连接失败”,这是什么鬼!?
- 编辑:BaseManager的文档是错误的!根本没有“start”方法!?!
- 编辑:几乎没有使用示例。
Pyro:
- 简单的远程对象
- 仅限网络通信(如果只是本地则是回环)
- 编辑:这个东西就是好用,而且它喜欢面向对象的共享,这让我很喜欢它
- 编辑:为什么这个不是标准库的一部分,而是那个试图模仿却失败的多进程垃圾?
编辑:我第一次回答这个问题时刚接触2.6版本的多进程。在下面的代码中,Texture类被注册并作为代理共享,但里面的“data”属性却没有。所以你猜会发生什么,每个进程都有一个单独的“data”属性副本,尽管你可能会期待不一样。我花了无数小时试图找出在运行时创建共享对象的好方法,但总是碰壁。这真让人困惑和沮丧。也许只是我,但看看别人尝试的稀少例子,似乎并不是这样。
我不得不痛苦地决定放弃多进程库,选择Pyro,直到多进程更成熟。虽然最开始我很兴奋Python内置了多进程,但现在我对它彻底失望,宁愿多次愉快地安装Pyro库,因为它是Python中如此美丽的库。
详细回答
我在过去的项目中使用过Pyro,感觉非常好。我也开始使用2.6新出的多进程。
在多进程中,我发现动态创建共享对象有点别扭。看起来在它的早期阶段,多进程模块更倾向于功能性编程,而不是面向对象。不过这并不完全正确,因为其实是可以做到的,只是我觉得“注册”调用让我感到受限。
例如:
manager.py:
from multiprocessing import Process
from multiprocessing.managers import BaseManager
class Texture(object):
def __init__(self, data):
self.data = data
def setData(self, data):
print "Calling set data %s" % (data)
self.data = data
def getData(self):
return self.data
class TextureManager(BaseManager):
def __init__(self, address=None, authkey=''):
BaseManager.__init__(self, address, authkey)
self.textures = {}
def addTexture(self, name, texture):
self.textures[name] = texture
def hasTexture(self, name):
return name in self.textures
server.py:
from multiprocessing import Process
from multiprocessing.managers import BaseManager
from manager import Texture, TextureManager
manager = TextureManager(address=('', 50000), authkey='hello')
def getTexture(name):
if manager.hasTexture(name):
return manager.textures[name]
else:
texture = Texture([0]*100)
manager.addTexture(name, texture)
manager.register(name, lambda: texture)
TextureManager.register("getTexture", getTexture)
if __name__ == "__main__":
server = manager.get_server()
server.serve_forever()
client.py:
from multiprocessing import Process
from multiprocessing.managers import BaseManager
from manager import Texture, TextureManager
if __name__ == "__main__":
manager = TextureManager(address=('127.0.0.1', 50000), authkey='hello')
manager.connect()
TextureManager.register("getTexture")
texture = manager.getTexture("texture2")
data = [2] * 100
texture.setData(data)
print "data = %s" % (texture.getData())
我所说的别扭感来自server.py,在这里我注册了一个getTexture函数,用于从TextureManager中获取某个名称的函数。回想起来,如果我把TextureManager做成一个可共享的对象,用于创建/获取可共享的纹理,可能就能消除这种别扭感。嗯,我还在尝试,但你明白我的意思。我不记得在使用Pyro时遇到过这种别扭感,但可能有比上面的例子更简洁的解决方案。