Heim >Backend-Entwicklung >Python-Tutorial >Fünf Möglichkeiten, den Singleton-Modus in Python zu implementieren
Singleton-Muster ist ein häufig verwendetes Software-Designmuster. Der Hauptzweck dieses Musters besteht darin, sicherzustellen, dass nur eine Instanz einer bestimmten Klasse vorhanden ist. Singleton-Objekte sind praktisch, wenn Sie möchten, dass nur eine Instanz einer bestimmten Klasse im gesamten System angezeigt wird.
Zum Beispiel werden die Konfigurationsinformationen eines Serverprogramms in einer Datei gespeichert und der Client liest die Konfigurationsdateiinformationen über eine AppConfig-Klasse. Wenn der Inhalt der Konfigurationsdatei während der Ausführung des Programms an vielen Stellen verwendet werden muss, müssen also an vielen Stellen Instanzen des AppConfig-Objekts erstellt werden, was zur Existenz mehrerer AppConfig-Instanzobjekte führt im System, und dies führt zu einer erheblichen Speicherverschwendung, insbesondere wenn die Konfigurationsdatei viel Inhalt enthält.
Tatsächlich hoffen wir für eine Klasse wie AppConfig, dass während der Ausführung des Programms nur ein Instanzobjekt vorhanden ist.
In Python können wir verschiedene Methoden verwenden, um das Singleton-Muster zu implementieren:
Das Folgende ist eine detaillierte Einführung:
Tatsächlich handelt es sich bei Python-Modulen um einen natürlichen Singleton-Modus, da das Modul beim ersten Import und beim Import eine .pyc-Datei generiert Beim zweiten Mal wird die .pyc-Datei direkt geladen, ohne dass der Modulcode erneut ausgeführt werden muss.
Wir müssen also nur die relevanten Funktionen und Daten in einem Modul definieren, um ein Singleton-Objekt zu erhalten.
Wenn wir wirklich eine Singleton-Klasse wollen, können wir Folgendes in Betracht ziehen:
class Singleton(object): def foo(self): pass singleton = Singleton()
Speichern Sie den obigen Code in der Datei mysingleton.py. Wenn Sie ihn verwenden möchten, importieren Sie die Objekte in dieser Datei direkt in andere Dateien Das Objekt ist das Objekt des Singleton-Modus Das Programm wird ausgeführt und das gedruckte Ergebnis lautet wie folgt:
from mysingleton import singletonEs scheint, dass es kein Problem gibt. Das liegt daran, dass die Ausführungsgeschwindigkeit zu hoch ist. Wenn die __init__-Methode einige E/A-Vorgänge enthält, treten Probleme auf.
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)
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
Das Problem tritt auf! Auf die oben beschriebene Weise erstellte Singletons unterstützen kein Multithreading.
Lösung: Sperren! Der entsperrte Teil wird gleichzeitig ausgeführt und der gesperrte Teil wird seriell ausgeführt, was die Geschwindigkeit verringert, aber die Datensicherheit gewährleistet.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 import threading 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 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0> <__main__.Singleton object at 0x02C933D0>
Das ist fast alles, aber es gibt immer noch ein kleines Problem, nämlich wenn das Programm ausgeführt wird, nachdem time.sleep(20) ausgeführt wurde und das Objekt unten instanziiert wird , es ist bereits ein Singleton-Muster.
Aber wir haben immer noch eine Sperre hinzugefügt, was nicht gut ist. Lassen Sie uns etwas optimieren und die Instanzmethode wie folgt ändern:def __init__(self): import time time.sleep(1)
<__main__.Singleton object at 0x034A3410> <__main__.Singleton object at 0x034BB990> <__main__.Singleton object at 0x034BB910> <__main__.Singleton object at 0x034ADED0> <__main__.Singleton object at 0x034E6BD0> <__main__.Singleton object at 0x034E6C10> <__main__.Singleton object at 0x034E6B90> <__main__.Singleton object at 0x034BBA30> <__main__.Singleton object at 0x034F6B90> <__main__.Singleton object at 0x034E6A90>
Der auf diese Weise implementierte Singleton-Modus unterliegt Einschränkungen bei der Verwendung. Die spätere Instanziierung muss über obj = Singleton.instance() erfolgen.
Wenn Sie obj = Singleton() verwenden, erhalten Sie auf diese Weise keine Singleton.Anhand des obigen Beispiels können wir erkennen, dass wir bei der Implementierung eines Singletons intern eine Sperre hinzufügen müssen, um die Thread-Sicherheit zu gewährleisten.
Wir wissen, dass wir beim Instanziieren eines Objekts zuerst die Methode __new__ der Klasse ausführen (wenn wir sie nicht schreiben, wird standardmäßig object.__new__ aufgerufen), um das Objekt zu instanziieren der Klasse wird initialisiert, sodass wir das Singleton-Muster darauf basierend implementieren können.
import time import threading class Singleton(object): _instance_lock = threading.Lock() def __init__(self): time.sleep(1) @classmethod def instance(cls, *args, **kwargs): with Singleton._instance_lock: 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() time.sleep(20) obj = Singleton.instance() print(obj)
Das gedruckte Ergebnis lautet wie folgt:
<__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110> <__main__.Singleton object at 0x02D6B110>Wenn Sie diesen Singleton-Modus verwenden und das Objekt in Zukunft instanziieren, ist die Methode zum Instanziieren des Objekts dieselbe wie üblich obj = Singleton().
Objekte werden von Klassen erstellt. Beim Erstellen eines Objekts wird die __init__-Methode der Klasse automatisch ausgeführt und object() führt die __call__-Methode der Klasse aus.
@classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): with Singleton._instance_lock: if not hasattr(Singleton, "_instance"): Singleton._instance = Singleton(*args, **kwargs) return Singleton._instance
import time import threading class Singleton(object): _instance_lock = threading.Lock() def __init__(self): time.sleep(1) @classmethod def instance(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): with Singleton._instance_lock: 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() time.sleep(20) obj = Singleton.instance() print(obj)
Implementieren des Singleton-Modus:
import threading class Singleton(object): _instance_lock = threading.Lock() def __init__(self): pass def __new__(cls, *args, **kwargs): if not hasattr(Singleton, "_instance"): with Singleton._instance_lock: if not hasattr(Singleton, "_instance"): Singleton._instance = object.__new__(cls) return Singleton._instance obj1 = Singleton() obj2 = Singleton() print(obj1,obj2) def task(arg): obj = Singleton() print(obj) for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start()
Das obige ist der detaillierte Inhalt vonFünf Möglichkeiten, den Singleton-Modus in Python zu implementieren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!