【问题标题】:Whether the method below is thread-safe when implementing Singleton pattern in python?在python中实现单例模式时,下面的方法是否是线程安全的?
【发布时间】:2014-03-25 14:19:51
【问题描述】:

我写了两个类。第一个类 MySingletonTSafe 是线程安全的,因为我使用 threading.Lock() 来控制如何调用创建实例的方法。但我不确定第二类 MySingletonNTSafe 是否是线程安全的。如果第二类是线程安全的,如何证明它不是线程安全的?

我找到了Creating a singleton in python 的帖子,但它无法解决我的难题。

以下是我的代码:

#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-


import threading
import Queue
import time
import random


class MySingletonTSafe(object):
    """implement Singleton pattern, thread-safe"""
    _instance = None
    _lock = threading.Lock()

    def __new__(cls):
        if MySingletonTSafe._instance is None:
            with MySingletonTSafe._lock:
                if MySingletonTSafe._instance is None:
                    MySingletonTSafe._instance = super(MySingletonTSafe, cls).__new__(cls)

        return MySingletonTSafe._instance

    def __init__(self):
        MySingletonTSafe._instance = self


class MySingletonNTSafe(object):
    """implement Singleton pattern, not-thread-safe"""
    _instance = None

    def __new__(cls):
        if MySingletonNTSafe._instance is None:
            # time.sleep(random.randint(1, 10))
            MySingletonNTSafe._instance = super(MySingletonNTSafe, cls).__new__(cls)

        return MySingletonNTSafe._instance

    def __init__(self):
        MySingletonNTSafe._instance = self


class Test(object):
    """Test whether the class MySingleton works"""
    def __init__(self, tnum=3):
        self.tnum = tnum
        self.queue_st = Queue.Queue()
        self.queue_nst = Queue.Queue()

    def run(self):
        threads_s = [threading.Thread(target=self._run_st) for i in xrange(self.tnum)]
        for t in threads_s:
            t.start()
            t.join()

        threads_ns = [threading.Thread(target=self._run_nst) for i in xrange(self.tnum)]
        for t in threads_ns:
            t.start()
            t.join()

    def _run_st(self):
        # thread-safe case
        obj = MySingletonTSafe()
        self.queue_st.put(obj)

    def _run_nst(self):
        # not-thread-safe case
        obj = MySingletonNTSafe()
        self.queue_nst.put(obj)


if __name__ == '__main__':
    test = Test(tnum=10)
    test.run()

    objs_st = []
    while not test.queue_st.empty():
        objs_st.append(test.queue_st.get())
    last = objs_st.pop()
    for obj in objs_st:
        if not last == obj:
            print('NOT IDENTICAL')
            break
        else:
            print('IDENTICAL')

    objs_nst = []
    while not test.queue_nst.empty():
        objs_nst.append(test.queue_nst.get())
    last = objs_nst.pop()
    for obj in objs_nst:
        if not last == obj:
            print('NOT IDENTICAL')
            break
        else:
            print('IDENTICAL')

【问题讨论】:

  • 嗯,名称和文档字符串是很好的线索。 """implement Singleton pattern, not-thread-safe"""
  • 嗨,我对线程安全单例也有同样的需求,并找到了this gist。 hth

标签: python multithreading python-2.7 singleton


【解决方案1】:

在这种情况下,您可以想出一个执行,其中MySingletonNTSafe 在多线程环境中做错事。这是一个:

  1. 线程 1 调用 MySingtonNTSafe()。它看到MySingletonNTSafe._instance is None,然后被打断。
  2. 线程 2 调用 MySingletonNTSafe()。它看到MySingletonNTSafe._instance 仍然是None,创建一个实例,将其分配给_instance,并返回它。
  3. 线程 1 恢复执行。它创建一个实例,将其分配给_instance,然后返回它。

此时,我们有两个实例,并且类已经失败。它不是线程安全的。

【讨论】:

  • 非常感谢。在我发布这个问题之前我已经知道你所指出的情况,我在 start() 后面写了 join() 是我的粗心......我编写了另一个测试类来证明 MySingletonNTSafe 不是线程安全的。修改后的代码为here。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2021-05-12
  • 2011-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多