Several realization methods and optimization details based on singleton pattern in Python
- 2020-06-23 00:57:58
- OfStack
The singleton pattern
The singleton pattern (Singleton Pattern) is a common software design pattern whose main purpose is to ensure that only 1 instance of a class exists. Singletons are useful when you want to have only one instance of a class in the system.
For example, the configuration information of a server program is stored in a file, and the client reads the configuration information through an AppConfig class. If there are many places where the contents of the configuration file need to be used while the program is running, that is, many places where instances of AppConfig objects need to be created, this results in multiple instance objects of AppConfig in the system, which can be a serious waste of memory resources, especially if the configuration file is very large. In fact, for a class like AppConfig, we want only one instance object to exist while the program is running.
In Python, there are several ways to implement the singleton pattern
Several ways to implement the singleton pattern
1. Use modules
In fact, the Python module is a natural singleton because the module generates a.pyc file on the first import and loads the.pyc file on the second import without executing the module code again. Therefore, we only need to define the relevant functions and data in a module, and we can get a singleton object. If we really want a singleton class, consider this:
mysingleton.py
class Singleton(object):
def foo(self):
pass
singleton = Singleton()
Save the above code in file mysingleton.py, and when you want to use it, import the object in this file directly into another file, which is a singleton object
from a import singleton
2. Use classes
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
In general, people think that this completes singleton mode, but this causes problems when using multithreading
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()
After the program is executed, the printing results are 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 doesn't seem to be a problem either, because the execution is too fast. If you have one IO operation in the init method, you will find a problem. Now we simulate it through ES42en.sleep
Let's add the following code to the method above with ___ 46EN__ :
def __init__(self): import time time.sleep(1)
After reexecuting the program, the results are 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>
Problem! The singleton created in the above manner does not support multithreading
Solution: Lock up! The unlocked part is executed concurrently, while the locked part is executed sequentially, which reduces the speed, but ensures data security
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)
The print results are 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>
That's about it, but there's one small problem. When the program executes, time.sleep (20), when we instantiate the object, it's already singleton mode, but we still lock it, it's not so good.
@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
This completes a singleton pattern that supports multiple threads
from a import singleton
0
The singleton pattern implemented in this way is limited in use and must be instantiated via obj = Singleton.instance ()
If you use obj=Singleton(), this is not a singleton
3. Based on the method of ___ (recommended and convenient)
From the above example, we can see that when we implement singletons, we need to add locks internally to ensure thread safety
We know that, when we instantiate an object, the method of the class with successie 84en__ (if we haven't written it, the default is to call object. It then executes the method of the class with succinit__ to initialize this object, so we can implement the singleton pattern based on this
from a import singleton
1
The print results are as follows:
from a import singleton
2
Using the singleton pattern in this way, when instantiating the object later, and when instantiating the object in the same way, obj = Singleton()
4. Implementation based on metaclass
The relevant knowledge
"""
1. Class by type Create, create class time type the __init__ Methods are automatically executed, class () perform type the __call__ methods ( Of the class __new__ methods , Of the class __init__ methods )
2. An object is created by a class __init__ Method automatically executes, object () The implementation of the class __call__ methods
"""
Example:
from a import singleton
4
Use of metaclasses
from a import singleton
5
Implement the singleton pattern
from a import singleton
6