Python単例モード
6666 ワード
概要
Singleton Patternは、クラスが1つのインスタンスしか存在しないことを保証することを主な目的とする一般的なソフトウェア設計モデルです.システム全体でクラスに1つのインスタンスしか表示されないことを望む場合は、単一のオブジェクトを使用できます.
例えば、あるサーバプログラムの構成情報は1つのファイルに格納され、クライアントはAppConfigのクラスを通じて構成ファイルの情報を読み出す.プログラムの実行中にコンフィギュレーション・ファイルのコンテンツを使用する必要がある場所が多い場合、つまりAppConfigオブジェクトのインスタンスを作成する必要がある場所が多いため、システムに複数のAppConfigのインスタンス・オブジェクトが存在し、特にコンフィギュレーション・ファイルのコンテンツが多い場合、メモリ・リソースが大幅に浪費されます.実際、AppConfigのようなクラスでは、プログラムの実行中にインスタンスオブジェクトが1つしか存在しないことを望んでいます.
モジュールを使用した単一モードの実装
実は、Pythonのモジュールは天然の単例モードです.モジュールは1回目のインポート時に
mysingleton.py:
上記のコードをファイル
アクセサリーを使う
印刷出力:
クラスの操作
一般的には、これで一例モードが完了すると考えられていますが、マルチスレッドを使用すると問題が発生し、印刷結果は以下の通りです.
実行速度が速すぎるため、initメソッドにIO操作がいくつかあると、問題が発見されます.次にtime.sleepシミュレーションでは、上記のinitメソッドに次のコードを追加しました.
プログラムを再実行すると、次の結果が得られます.
以上のように作成した単一の例では、マルチスレッドをサポートできないという問題が発生しました.解決策:ロックをかける.ロックされていない部分は同時に実行され、ロックされている部分は直列に実行され、速度は低下したが、データの安全を保証した.
改造new方法
印刷出力:
ロック操作コードは以下の通りです.
Singleton Patternは、クラスが1つのインスタンスしか存在しないことを保証することを主な目的とする一般的なソフトウェア設計モデルです.システム全体でクラスに1つのインスタンスしか表示されないことを望む場合は、単一のオブジェクトを使用できます.
例えば、あるサーバプログラムの構成情報は1つのファイルに格納され、クライアントはAppConfigのクラスを通じて構成ファイルの情報を読み出す.プログラムの実行中にコンフィギュレーション・ファイルのコンテンツを使用する必要がある場所が多い場合、つまりAppConfigオブジェクトのインスタンスを作成する必要がある場所が多いため、システムに複数のAppConfigのインスタンス・オブジェクトが存在し、特にコンフィギュレーション・ファイルのコンテンツが多い場合、メモリ・リソースが大幅に浪費されます.実際、AppConfigのようなクラスでは、プログラムの実行中にインスタンスオブジェクトが1つしか存在しないことを望んでいます.
モジュールを使用した単一モードの実装
実は、Pythonのモジュールは天然の単例モードです.モジュールは1回目のインポート時に
.pyc
ファイルを生成し、2回目のインポート時に.pyc
ファイルを直接ロードし、モジュールコードを再実行しないからです.したがって,関連する関数とデータを1つのモジュールに定義するだけで,単一のオブジェクトを得ることができる.本当に単一のクラスがほしい場合は、次のことを考えてみましょう.mysingleton.py:
class Singleton(object):
def foo(self):
pass
singleton = Singleton()
上記のコードをファイル
mysingleton.py
に保存し、使用する場合は、このファイルのオブジェクトを他のファイルに直接インポートします.このオブジェクトは、単一のモードのオブジェクトです.from a import singleton
アクセサリーを使う
def Singleton(cls):
_instance = {}
def _singleton(*args, **kargs):
if cls not in _instance:
_instance[cls] = cls(*args, **kargs)
return _instance[cls]
return _singleton
@Singleton
class A(object):
a = 1
def __init__(self, x=0):
self.x = x
a1 = A(2)
a2 = A(3)
print("a1: ", a1, "a1.x: ", a1.x)
print("a2: ", a2, "a2.x: ", a2.x)
印刷出力:
a1: <__main__.a object="" at=""> a1.x: 2
a2: <__main__.a object="" at=""> a2.x: 2
クラスの操作
import threading
class Singleton(object):
def __init__(self):
pass
@classmethod
def instance(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
def task(arg):
obj = Singleton.instance()
print(obj)
for i in range(10):
t = threading.Thread(target=task,args=[i,])
t.start()
一般的には、これで一例モードが完了すると考えられていますが、マルチスレッドを使用すると問題が発生し、印刷結果は以下の通りです.
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
実行速度が速すぎるため、initメソッドにIO操作がいくつかあると、問題が発見されます.次にtime.sleepシミュレーションでは、上記のinitメソッドに次のコードを追加しました.
def __init__(self):
import time
time.sleep(1)
プログラムを再実行すると、次の結果が得られます.
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
<__main__.singleton object="" at="">
以上のように作成した単一の例では、マルチスレッドをサポートできないという問題が発生しました.解決策:ロックをかける.ロックされていない部分は同時に実行され、ロックされている部分は直列に実行され、速度は低下したが、データの安全を保証した.
import threading
import time
class Singleton(object):
_instance_lock = threading.Lock()
def __init__(self):
time.sleep(0.1)
@classmethod
def instance(cls, *args, **kwargs):
with Singleton._instance_lock:
if not hasattr(Singleton, "_instance"):
Singleton._instance = Singleton(*args, **kwargs)
return Singleton._instance
import threading
def task(arg):
obj = Singleton.instance()
print(obj)
threads = []
for i in range(10):
t = threading.Thread(target=task,args=[i,])
threads.append(t)
[t.start() for t in threads]
[t.join() for t in threads]
obj = Singleton.instance()
print("obj: ", obj)
改造new方法
class Singleton:
instance = None
init_flag = False
def __new__(cls, *args, **kwargs):
if cls.instance is None:
cls.instance = super().__new__(cls)
return cls.instance
def __init__(self, x):
if Singleton.init_flag:
return
self.x = x
Singleton.init_flag = True
s1 = Singleton(1)
s2 = Singleton(2)
print("s1: ", s1, "s1.x: ", s1.x)
print("s2: ", s2, "s2.x: ", s2.x)
印刷出力:
s1: <__main__.singleton object="" at=""> s1.x: 1
s2: <__main__.singleton object="" at=""> s2.x: 1
ロック操作コードは以下の通りです.
import threading
import time
class Singleton:
instance = None
init_flag = False
_instance_lock = threading.Lock()
_instance_lock2 = threading.Lock()
def __new__(cls, *args, **kwargs):
with Singleton._instance_lock:
if cls.instance is None:
time.sleep(0.1)
cls.instance = super().__new__(cls)
return cls.instance
def __init__(self, x):
with Singleton._instance_lock2:
if Singleton.init_flag:
return
self.x = x
Singleton.init_flag = True
def task(i):
s = Singleton(i)
print("s: ", s, "s.x: ", s.x)
# print("s dir: ", dir(s))
threads = []
for i in range(10):
t = threading.Thread(target=task, args=(1,))
threads.append(t)
[t.start() for t in threads]
[t.join() for t in threads]