使用具有 multiprocessing.Manager 的上下文管理器有什么好处?
What is the benefit of using a context mananger with multiprocessing.Manager?
在 the documentation 中,管理器与上下文管理器(即 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
But what is the benefit of this (...)?
首先,您可以获得几乎所有上下文管理器的主要好处。您有明确定义的资源生命周期。它是在 with ...:
块打开时分配和获取的。它在块结束时被释放(到达末尾或因为引发异常)。每当垃圾收集器找到它时,它仍然会被释放,但由于外部资源已经被释放,所以这不太重要。
在 multiprocessing.Manager
的情况下(这是一个 returns 和 SyncManager
的函数,尽管 Manager
看起来很像 class),资源是一个 "server" 进程,它保存状态和一些共享该状态的工作进程。
what is [the benefit of using a context manager] for Manager?
如果您不使用上下文管理器并且不在管理器上调用关闭,那么 "server" 进程将继续 运行ning 直到 SyncManager
的 __del__
是 运行。在某些情况下,这可能会在创建 SyncManager
的代码完成后不久发生(例如,如果它是在一个短函数内创建的,而函数 returns 正常并且您正在使用 CPython 那么引用计数系统可能会很快注意到对象已经死了并调用它的 __del__
)。在其他情况下,它可能需要更长的时间(如果引发异常并保留对管理器的引用,那么它将保持活动状态直到处理该异常)。在一些糟糕的情况下,它可能根本不会发生(如果 SyncManager
结束在一个引用循环中,那么它的 __del__
将阻止循环收集器收集它 根本; 或者您的进程可能会在调用 __del__
之前崩溃)。在所有这些情况下,您将放弃对 SyncManager
创建的额外 Python 进程何时被清理的控制权。这些进程可能代表您系统上的重要资源使用情况。在非常糟糕的情况下,如果您在循环中创建 SyncManager
,您最终可能会创建许多同时存在的对象,并且很容易消耗大量资源。
If you don't use it in a context, what steps do you have to use to ensure that everything is closed properly?
您必须自己实施上下文管理器协议,就像您在没有 with
的情况下使用的任何上下文管理器一样。在 pure-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__
的别名。
在 the documentation 中,管理器与上下文管理器(即 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
But what is the benefit of this (...)?
首先,您可以获得几乎所有上下文管理器的主要好处。您有明确定义的资源生命周期。它是在 with ...:
块打开时分配和获取的。它在块结束时被释放(到达末尾或因为引发异常)。每当垃圾收集器找到它时,它仍然会被释放,但由于外部资源已经被释放,所以这不太重要。
在 multiprocessing.Manager
的情况下(这是一个 returns 和 SyncManager
的函数,尽管 Manager
看起来很像 class),资源是一个 "server" 进程,它保存状态和一些共享该状态的工作进程。
what is [the benefit of using a context manager] for Manager?
如果您不使用上下文管理器并且不在管理器上调用关闭,那么 "server" 进程将继续 运行ning 直到 SyncManager
的 __del__
是 运行。在某些情况下,这可能会在创建 SyncManager
的代码完成后不久发生(例如,如果它是在一个短函数内创建的,而函数 returns 正常并且您正在使用 CPython 那么引用计数系统可能会很快注意到对象已经死了并调用它的 __del__
)。在其他情况下,它可能需要更长的时间(如果引发异常并保留对管理器的引用,那么它将保持活动状态直到处理该异常)。在一些糟糕的情况下,它可能根本不会发生(如果 SyncManager
结束在一个引用循环中,那么它的 __del__
将阻止循环收集器收集它 根本; 或者您的进程可能会在调用 __del__
之前崩溃)。在所有这些情况下,您将放弃对 SyncManager
创建的额外 Python 进程何时被清理的控制权。这些进程可能代表您系统上的重要资源使用情况。在非常糟糕的情况下,如果您在循环中创建 SyncManager
,您最终可能会创建许多同时存在的对象,并且很容易消耗大量资源。
If you don't use it in a context, what steps do you have to use to ensure that everything is closed properly?
您必须自己实施上下文管理器协议,就像您在没有 with
的情况下使用的任何上下文管理器一样。在 pure-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__
的别名。