我在Python 3.6中进行了以下设置,用于进程间通信:
from multiprocessing.managers import BaseManager
class MyManager(BaseManager): pass
MyManager.register('get_instance', callable=lambda:my_instance)
m = MyManager(address=('', 50000), authkey=b'key')
s = m.get_server()
s.serve_forever()
为了避免阻塞较大应用程序的消息循环,我使用了一个线程来包含此设置。因此s.serve_forever()
实际上在线程的run
函数中运行。
这是根据文档完成的。并且设置本身在客户端管理器调用共享实例时工作正常。
但是,我发现没有办法停止这个"serve_forever"服务器。由于文档没有提到这一点,我检查了源代码。有一个stop_event
据说我可以set
退出循环。但它没有奏效,因为accepter
守护程序/线程仍在运行。而且我无法在服务器对象上调用shutdown
,因为我没有套接字对象c
。
那么如何关闭此服务器呢?
使用BaseManager.start()
对我来说并不是一个真正的选择,因为在我的情况下,服务器共享一个异步消息循环,该循环只能由启动进程访问。BaseManager.start()
会生成一个不再有权访问消息循环的新进程。 另一方面,get_server().serve_forever()
在调用进程中运行。
在服务器中尝试此操作:
import threading
s = m.get_server()
stop_timer = threading.Timer(1, lambda:s.stop_event.set())
MyManager.register('stop', callable=lambda:stop_timer.start())
s.serve_forever()
在客户端中:
MyManager.register('stop')
m.stop()
更新:
我通过延迟stop_event.set()
解决了超时问题threading.Timer
老:
但是,在机器上,由于stop()
方法无法接收数据,您会遇到长时间的超时,这个答案谈到了这一点 - 但我无法让它工作:
正确断开多处理遥控器的连接
我是多处理管理器的新手,如果我找到更好的解决方案,我会更新这个答案。(更新:找到,更新(
这是读取multiprocessing.managers
源后的黑客攻击,从_finalize_manager()
中剥离,基本上是创建与服务器的连接并发送关机消息
from multiprocessing.managers import dispatch,listener_client
_Client = listener_client['pickle'][1]
# address and authkey same as when started the manager
conn = _Client(address=('127.0.0.1', 50000), authkey=b'key')
dispatch(conn, None, 'shutdown')
conn.close()
你可以包装/使用管理器启动/关闭来避免这个永远运行的服务器(start((为你启动一个服务器(:
m = MyManager(address=('', 50000), authkey=b'key')
m.start()
# do something
m.shutdown()