在Multiprocessing中创建Singleton类

时间:2017-07-13 09:46:45

标签: python python-2.7 singleton multiprocessing metaclass

我使用 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 方法

1 个答案:

答案 0 :(得分:2)

每个子进程都运行自己的Python解释器实例,因此一个进程中的SingletonType不会与另一个进程中的状态共享。这意味着只存在于您的一个进程中的真正单例将没什么用处,因为您将无法在其他进程中使用它:虽然您可以manually share data between processes,但仅限于基本数据类型(例如dicts和列表)。

不要依赖单身人士,只需在流程之间共享基础数据:

#!/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://stackoverflow.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通常非常有用。