Advantages and disadvantages of Several implementation methods of the singleton mode in Python, and advantages and disadvantages of python
Singleton Mode
Singleton Pattern)Is a commonly used software design model, the main purpose of this model is to ensureA class only has one instance.. When you want to create only one instance for a class in the system, the single-instance object can be used.
For example, the configuration information of a server program is stored in a file, and the client reads the configuration file information through an AppConfig class. If the content of the configuration file needs to be used in many places during the program running, that is, the AppConfig object instance needs to be created in many places, this results in multiple AppConfig instance objects in the system, which seriously wastes memory resources, especially when the configuration file contains a lot of content. In fact, for classes like AppConfig, we hope that only one instance object exists during the program running.
In Python, we can use multiple methods to implement the singleton mode.
Methods for implementing Singleton Mode 1. Use modules
In fact,The Python module is the natural Singleton mode.Because the module will generate.pyc
File. When the second import is performed, the file is directly loaded..pyc
File, instead of executing the module code again. Therefore, we only need to define the relevant functions and data in a module to obtain a singleton object. If we really want a singleton class, consider doing this:
Mysingleton. py
class Singleton(object): def foo(self): passsingleton = Singleton()
Save the above Code in the filemysingleton.py
To be used, directly import the objects in this file into other files. This object is an object in singleton mode.
from a import singleton
2. Usage class
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
Generally, the singleton mode is completed in this way, but there will be problems when multithreading is used.
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._instanceimport threadingdef task(arg): obj = Singleton.instance() print(obj)for i in range(10): t = threading.Thread(target=task,args=[i,]) t.start()
After the program is executed, the output is as follows:
<__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>
It seems that there is no problem, because the execution speed is too fast. If there are some IO operations in the init method, we will find the problem. Next we use time. sleep to simulate
Add the following code to the _ init _ method above:
def __init__(self): import time time.sleep(1)
After the program is re-executed, the result is as follows:
<__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>
The problem has occurred! The Single Instance created in the preceding method cannot support multithreading.
Solution: Lock! Concurrent execution without locks, serial execution with locks, and lower speed, but ensures data security
import timeimport threadingclass 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._instancedef 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)
The output is as follows:
<__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>
This is almost the case, but there is still a small problem, that is, when the program is executed, the time is executed. after sleep (20), when the following object is instantiated, It is a singleton mode now, but we still apply the lock. This is not very good. Then we will perform some optimization and use the intance method, just change it to the following:
@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
In this way, a singleton mode that supports multithreading is complete.
Import timeimport threadingclass 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. _ instancedef 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)Complete code
In this way, the Singleton mode is restricted during use. In future instantiation, you must use obj = Singleton. instance ()
If obj = Singleton () is used, this method is not used as a Singleton.
3. Implementation Based on the _ new _ Method
Through the above example, we can know that when we implement Singleton,To ensure thread security, you need to add a lock internally.
We know that when we instantiate an objectFirst, the _ new _ method of the class is executed.(When we do not write data, object. _ new _ is called by default __),Instantiate object; ThenExecute the _ init _ method of the class.To initialize this object. All of us can implement the singleton mode based on this.
import threadingclass 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, *args, **kwargs) return Singleton._instanceobj1 = 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()
The output is as follows:
<__main__.Singleton object at 0x038B33D0> <__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0><__main__.Singleton object at 0x038B33D0>
This Singleton mode is used. When an object is instantiated in the future, obj = Singleton () is the same as the method used to instantiate the object in the future ()
4. Implement Related Knowledge Based on metaclass
"1. class is created by type. When a class is created, the _ init _ method of the type is automatically executed, and the class () execute the _ call _ method of type (the _ new _ method of the class and the _ init _ method of the class) 2. an object is created by a class. when an object is created, the _ init _ method of the class is automatically executed. The _ call _ method of the object () Execution class """
Example:
Class Foo: def _ init _ (self): pass def _ call _ (self, * args, ** kwargs): passobj = Foo () # execute the _ call _ method of type and call the _ new _ method of the Foo class (Object of type) to create an object, call the _ init _ method of the Foo class (Object of type) to initialize the object. Obj () # execute the _ call _ method of Foo.
Usage of metadata
Class SingletonType (type): def _ init _ (self, * args, ** kwargs): super (SingletonType, self ). _ init _ (* args, ** kwargs) def _ call _ (cls, * args, ** kwargs): # cls, that is, print ('cls', cls) obj = cls. _ new _ (cls, * args, ** kwargs) cls. _ init _ (obj, * args, ** kwargs) # Foo. _ init _ (obj) return objclass Foo (metaclass = SingletonType): # specify the type of the created Foo as SingletonType def _ init _ (self ): pass def _ new _ (cls, * args, ** kwargs): return object. _ new _ (cls, * args, ** kwargs) obj = Foo ()
Implement Singleton Mode
import threadingclass SingletonType(type): _instance_lock = threading.Lock() def __call__(cls, *args, **kwargs): if not hasattr(cls, "_instance"): with SingletonType._instance_lock: if not hasattr(cls, "_instance"): cls._instance = super(SingletonType,cls).__call__(*args, **kwargs) return cls._instanceclass Foo(metaclass=SingletonType): def __init__(self,name): self.name = nameobj1 = Foo('name')obj2 = Foo('name')print(obj1,obj2)