在多处理中创建单例类
Posted
技术标签:
【中文标题】在多处理中创建单例类【英文标题】:Make Singleton class in Multiprocessing 【发布时间】:2017-12-18 00:35:27 【问题描述】:我使用 Metaclass 创建 Singleton 类,它在多线程中运行良好并且只创建 MySingleton 类的一个实例,但在多处理中,它总是创建新实例
import multiprocessing
class SingletonType(type):
# meta class for making a class singleton
def __call__(cls, *args, **kwargs):
try:
return cls.__instance
except AttributeError:
cls.__instance = super(SingletonType, cls).__call__(*args, **kwargs)
return cls.__instance
class MySingleton(object):
# singleton class
__metaclass__ = SingletonType
def __init__(*args,**kwargs):
print "init called"
def task():
# create singleton class instance
a = MySingleton()
# create two process
pro_1 = multiprocessing.Process(target=task)
pro_2 = multiprocessing.Process(target=task)
# start process
pro_1.start()
pro_2.start()
我的输出:
init called
init called
我需要 MySingleton 类 init 方法只被调用一次
【问题讨论】:
这里为什么需要元类? 我在上面的代码中使用元类制作单例类我创建“SingletonType”元类,MySingleton 是单例类 与线程不同的进程不共享上下文(它们在分叉时都会创建它的副本)。如果你想在进程之间交换数据,你应该在这里查看 IPC。 本机对象不会在进程之间共享(由于引用计数)。 @TomWyllie:不是第一次想要单例的人们提出元类。一些来自另一种语言的人可能写了一个流行的文档来暗示这种模式。我通常不赞成打人,但在这种情况下,我想知道...... 【参考方案1】:您的每个子进程都运行自己的 Python 解释器实例,因此一个进程中的 SingletonType
不会与另一个进程中的那些共享其状态。这意味着只存在于您的一个进程中的真正单例将几乎没有用处,因为您将无法在其他进程中使用它:虽然您可以manually share data between processes,但仅限于基本数据类型(例如字典和列表)。
不要依赖单例,只需在进程之间共享底层数据:
#!/usr/bin/env python3
import multiprocessing
import os
def log(s):
print(': '.format(os.getpid(), s))
class PseudoSingleton(object):
def __init__(*args,**kwargs):
if not shared_state:
log('Initializating shared state')
with shared_state_lock:
shared_state['x'] = 1
shared_state['y'] = 2
log('Shared state initialized')
else:
log('Shared state was already initalized: '.format(shared_state))
def task():
a = PseudoSingleton()
if __name__ == '__main__':
# We need the __main__ guard so that this part is only executed in
# the parent
log('Communication setup')
shared_state = multiprocessing.Manager().dict()
shared_state_lock = multiprocessing.Lock()
# create two process
log('Start child processes')
pro_1 = multiprocessing.Process(target=task)
pro_2 = multiprocessing.Process(target=task)
pro_1.start()
pro_2.start()
# Wait until processes have finished
# See https://***.com/a/25456494/857390
log('Wait for children')
pro_1.join()
pro_2.join()
log('Done')
打印出来
16194: Communication setup
16194: Start child processes
16194: Wait for children
16200: Initializating shared state
16200: Shared state initialized
16201: Shared state was already initalized: 'x': 1, 'y': 2
16194: Done
但是,根据您的问题设置,使用其他进程间通信机制可能会有更好的解决方案。例如,Queue
class 通常非常有用。
【讨论】:
但我创建了 PseudoSingleton 类“a”和“b”的两个实例并尝试打印 a is b 它返回 False,这意味着 PseudoSingleton 不完全是 Singleton 类我总是得到新实例 正如我所说,您不能在进程之间共享对象实例。这意味着您将在每个子进程中至少有一个单独的类实例。这些不能共享它们的内部状态(它们的属性),但它们可以使用单独定义的共享状态(在我的示例中为shared_state
)。这样一来,您的实例将不是真正的单例,但仍会表现得像一个(因为它们在相同的共享数据上运行)。
我可以重新初始化 PseudoSingleton 类的所有变量,意思是我可以手动设置或重置 shared_state_lock 锁以上是关于在多处理中创建单例类的主要内容,如果未能解决你的问题,请参考以下文章