在文档中,管理器与上下文管理器(即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 = MyManager()
maths = manager.Maths()
print(maths.add(4, 3)) # prints 7
print(maths.mul(7, 8)) # prints 56
但是这样做有什么好处(...)?
首先,您可以获得几乎所有上下文管理器的主要好处。 您为资源定义了明确定义的生存期。 它在打开with ...:
块时分配和获取。 当块结束时(通过到达终点或因为引发异常)时,它会释放。 每当垃圾回收器处理它时,它仍然会被释放,但这不太重要,因为外部资源已经释放。
在multiprocessing.Manager
(这是一个返回SyncManager
的函数,即使Manager
看起来很像一个类)的情况下,资源是一个"服务器"进程,它保存状态和许多共享该状态的工作进程。
的 [使用上下文管理器的好处] 是什么?
如果您不使用上下文管理器并且没有在管理器上调用关闭,则"服务器"进程将继续运行,直到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__
的别名。