在Python中,如果要创建一个单例,通常有两种方式。
第一种,利用python的模块的特性,先创建一个对象,其他的模块通过导入此模块,来实现单例。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  | class SingleCls:
    def __init__(self):
        self.__info_list = list()
        # self.__info_list = multiprocessing.Manager().list()
    def AddMessage(self, message):
        self.__info_list.append("Hello %s" % message)
    def __repr__(self):
        return str(self.__info_list)
single_obj = SingleCls()
  | 
另一种,使用python一切皆对象的属性,类也属于对象,使用类中的类属性来保存创建好的单例。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
  | class SingleCls:
    _instance = None
    def __new__(cls, *args, **kw):
        if not cls._instance:
            cls._instance = super(SingleCls, cls).__new__(cls, *args, **kw)
        return cls._instance
    def __init__(self):
        self.__info_list = list()
    def AddMessage(self, message):
        self.__info_list.append("Hello %s" % message)
    def __repr__(self):
        return str(self.__info_list)
single_obj = SingleCls()
  | 
单例的本质是,不同模块使用的是同一个对象,这需要在 ‘第三方’ 的领土上创建。
可是在多进程的环境中,结果却不一定了。
- 多进程的环境中,子进程通过fork产生,会拷贝父进程中的变量,单例也不例外。
 - 所以,子进程中的单例对象,已经各不相同了!
 - 导致的结果就是,虽然子进程中对单例对象进行了很多操作,但是父进程中的单例对象却未发生改变。
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
  | def func(m):
    single_obj.AddMessage(m)
    print("single_obj {m} -> ".format(m=m), single_obj)
func("1")
func("2")
func("3")
pool = multiprocessing.Pool(4)
pool.apply(func, args=("First",))
pool.apply(func, args=("Second",))
pool.apply(func, args=("Third",))
# pool.apply(single_obj.AddMessage, args=("First",))
# pool.apply(single_obj.AddMessage, args=("Second",))
# pool.apply(single_obj.AddMessage, args=("Third",))
pool.close()
pool.join()
print(single_obj)
  | 
输出如下所示:
1
2
3
4
5
6
7
  | single_obj 1 ->  ['Hello 1']
single_obj 2 ->  ['Hello 1', 'Hello 2']
single_obj 3 ->  ['Hello 1', 'Hello 2', 'Hello 3']
single_obj First ->  ['Hello 1', 'Hello 2', 'Hello 3', 'Hello First']
single_obj Second ->  ['Hello 1', 'Hello 2', 'Hello 3', 'Hello Second']
single_obj Third ->  ['Hello 1', 'Hello 2', 'Hello 3', 'Hello Third']
['Hello 1', 'Hello 2', 'Hello 3']
  | 
Author
Alfons
LastMod
2019-06-26
License
Creative Commons BY-NC-ND 3.0