在the documentation中,Manager与上下文管理器(即with
)一起使用,如下所示:
from multiprocessing.managers import BaseManager
class MathsClass:
def add(self, x, y):
return x + y
def mul(self, x, y):
return x * y
class MyManager(BaseManager):
pass
MyManager.register('Maths', MathsClass)
if __name__ == '__main__':
with MyManager() as manager:
maths = manager.Maths()
print(maths.add(4, 3)) # prints 7
print(maths.mul(7, 8)) # prints 56
但是除了名称空间之外,这有什么好处?对于打开文件流,好处很明显,因为您不必手动.close()
连接,但它对于Manager来说是什么?如果您不在上下文中使用它,您必须使用哪些步骤来确保所有内容都正确关闭?
简而言之,使用上述内容有什么好处:
manager = MyManager()
maths = manager.Maths()
print(maths.add(4, 3)) # prints 7
print(maths.mul(7, 8)) # prints 56
但这有什么好处(...)?
首先,您将获得几乎所有上下文管理器的主要优势。您有一个明确定义的资源生命周期。当with ...:
块打开时,它被分配和获取。当块结束时(通过到达结束或因为引发异常)它被释放。每当垃圾收集器到达它时它仍然被释放,但由于外部资源已经被释放,因此不太重要。
在multiprocessing.Manager
(这是一个返回SyncManager
的函数,即使Manager
看起来很像一个类)的情况下,资源是一个“服务器”进程,它保存状态和许多共享该状态的工作进程。
什么是[使用上下文管理器的好处]为Manager?
如果你不使用上下文管理器而你没有在管理器上调用shutdown,那么“server”进程将继续运行,直到运行SyncManager
的__del__
。在某些情况下,这可能在创建SyncManager
的代码完成后很快发生(例如,如果它是在一个短函数内创建并且函数正常返回并且您正在使用CPython那么引用计数系统可能会很快注意到对象已死,并称其为__del__
)。在其他情况下,可能需要更长的时间(如果引发异常并保留对管理器的引用,那么它将保持活动直到处理该异常)。在一些不好的情况下,它可能永远不会发生(如果SyncManager
最终在参考周期中,那么它的__del__
将阻止循环收集器收集它;或者你的进程可能会在调用__del__
之前崩溃)。在所有这些情况下,您将放弃控制SyncManager
创建的额外Python进程何时被清除。这些过程可能代表您系统上的非平凡资源使用情况。在非常糟糕的情况下,如果你在一个循环中创建SyncManager
,你最终可能会创建许多同时存在的这些并且可能很容易消耗大量资源。
如果您不在上下文中使用它,您必须使用哪些步骤来确保所有内容都正确关闭?
您必须自己实现上下文管理器协议,就像您在没有with
时使用的任何上下文管理器一样。在纯Python中做这件事虽然仍然是正确的但是很棘手。就像是:
manager = None
try:
manager = MyManager()
manager.__enter__()
# use it ...
except:
if manager is not None:
manager.__exit__(*exc_info())
else:
if manager is not None:
manager.__exit__(None, None, None)
start
和shutdown
也分别是__enter__
和__exit__
的别名。