Last active
September 23, 2019 22:53
-
-
Save sodastsai/0e6c94990771d21dc95a8e1bd4606eae to your computer and use it in GitHub Desktop.
Python singleton metaclass (thread-safe)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import absolute_import, division, print_function, unicode_literals | |
from multiprocessing.dummy import Pool as ThreadPool | |
from multiprocessing import Lock | |
from threading import get_ident | |
class SingletonType(type): | |
def __new__(mcs, name, bases, attrs): | |
# Assume the target class is created (i.e. this method to be called) in the main thread. | |
cls = super(SingletonType, mcs).__new__(mcs, name, bases, attrs) | |
cls.__shared_instance_lock__ = Lock() | |
return cls | |
def __call__(cls, *args, **kwargs): | |
with cls.__shared_instance_lock__: | |
try: | |
return cls.__shared_instance__ | |
except AttributeError: | |
cls.__shared_instance__ = super(SingletonType, cls).__call__(*args, **kwargs) | |
return cls.__shared_instance__ | |
class NonThreadSafeSingletonType(type): | |
def __call__(cls, *args, **kwargs): | |
try: | |
return cls.__shared_instance__ | |
except AttributeError: | |
cls.__shared_instance__ = super(NonThreadSafeSingletonType, cls).__call__(*args, **kwargs) | |
return cls.__shared_instance__ | |
def run(DatabaseClass): | |
result_set = set() | |
result_set_access_lock = Lock() | |
def worker(_result_set, _result_set_access_lock): | |
db = DatabaseClass() | |
with _result_set_access_lock: | |
_result_set.add(db) | |
thread_pool = ThreadPool(10) | |
for i in six.moves.range(100): | |
thread_pool.apply_async(worker, (result_set, result_set_access_lock)) | |
thread_pool.close() | |
thread_pool.join() | |
print(result_set) | |
print(len(result_set)) | |
if __name__ == "__main__": | |
import six | |
class DatabaseBase(object): | |
def __init__(self): | |
super(DatabaseBase, self).__init__() | |
print("Created in thread: {}".format(get_ident())) | |
def __repr__(self): | |
return "<A database>" | |
@six.add_metaclass(SingletonType) | |
class Database(DatabaseBase): | |
pass | |
@six.add_metaclass(NonThreadSafeSingletonType) | |
class NonThreadSafeDatabase(DatabaseBase): | |
pass | |
class NonSingletonDatabase(DatabaseBase): | |
pass | |
print("Thread-safe Singleton =============================") | |
run(Database) | |
print("Thread-safe Singleton =============================\n\n") | |
print("Non-Thread-safe Singleton =========================") | |
run(NonThreadSafeDatabase) | |
print("Non-Thread-safe Singleton =========================\n\n") | |
print("Normal ============================================") | |
run(NonSingletonDatabase) | |
print("Normal ============================================\n\n") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Thread-safe Singleton ============================= | |
Created in thread: 123145307557888 | |
{<A database>} | |
1 | |
Thread-safe Singleton ============================= | |
Non-Thread-safe Singleton ========================= | |
Created in thread: 123145307557888 | |
Created in thread: 123145312813056 | |
Created in thread: 123145323323392 | |
Created in thread: 123145339088896 | |
Created in thread: 123145344344064 | |
Created in thread: 123145354854400 | |
Created in thread: 123145328578560 | |
Created in thread: 123145349599232 | |
Created in thread: 123145333833728 | |
Created in thread: 123145318068224 | |
{<A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>} | |
10 | |
Non-Thread-safe Singleton ========================= | |
Normal ============================================ | |
Created in thread: 123145307557888 | |
Created in thread: 123145312813056 | |
Created in thread: 123145323323392 | |
Created in thread: 123145333833728 | |
Created in thread: 123145344344064 | |
Created in thread: 123145354854400 | |
Created in thread: 123145318068224 | |
Created in thread: 123145339088896 | |
Created in thread: 123145307557888 | |
Created in thread: 123145349599232 | |
Created in thread: 123145312813056 | |
Created in thread: 123145328578560 | |
Created in thread: 123145323323392 | |
Created in thread: 123145333833728 | |
Created in thread: 123145344344064 | |
Created in thread: 123145354854400 | |
Created in thread: 123145318068224 | |
Created in thread: 123145339088896 | |
Created in thread: 123145307557888 | |
Created in thread: 123145349599232 | |
Created in thread: 123145312813056 | |
Created in thread: 123145328578560 | |
Created in thread: 123145323323392 | |
Created in thread: 123145333833728 | |
Created in thread: 123145344344064 | |
Created in thread: 123145354854400 | |
Created in thread: 123145318068224 | |
Created in thread: 123145339088896 | |
Created in thread: 123145307557888 | |
Created in thread: 123145349599232 | |
Created in thread: 123145312813056 | |
Created in thread: 123145328578560 | |
Created in thread: 123145323323392 | |
Created in thread: 123145333833728 | |
Created in thread: 123145344344064 | |
Created in thread: 123145354854400 | |
Created in thread: 123145318068224 | |
Created in thread: 123145339088896 | |
Created in thread: 123145307557888 | |
Created in thread: 123145349599232 | |
Created in thread: 123145312813056 | |
Created in thread: 123145328578560 | |
Created in thread: 123145323323392 | |
Created in thread: 123145333833728 | |
Created in thread: 123145344344064 | |
Created in thread: 123145354854400 | |
Created in thread: 123145318068224 | |
Created in thread: 123145339088896 | |
Created in thread: 123145307557888 | |
Created in thread: 123145349599232 | |
Created in thread: 123145312813056 | |
Created in thread: 123145328578560 | |
Created in thread: 123145333833728 | |
Created in thread: 123145344344064 | |
Created in thread: 123145354854400 | |
Created in thread: 123145323323392 | |
Created in thread: 123145307557888 | |
Created in thread: 123145349599232 | |
Created in thread: 123145339088896 | |
Created in thread: 123145333833728 | |
Created in thread: 123145344344064 | |
Created in thread: 123145312813056 | |
Created in thread: 123145328578560 | |
Created in thread: 123145349599232 | |
Created in thread: 123145339088896 | |
Created in thread: 123145354854400 | |
Created in thread: 123145323323392 | |
Created in thread: 123145307557888 | |
Created in thread: 123145328578560 | |
Created in thread: 123145333833728 | |
Created in thread: 123145344344064 | |
Created in thread: 123145312813056 | |
Created in thread: 123145318068224 | |
Created in thread: 123145349599232 | |
Created in thread: 123145339088896 | |
Created in thread: 123145333833728 | |
Created in thread: 123145344344064 | |
Created in thread: 123145328578560 | |
Created in thread: 123145354854400 | |
Created in thread: 123145323323392 | |
Created in thread: 123145339088896 | |
Created in thread: 123145333833728 | |
Created in thread: 123145312813056 | |
Created in thread: 123145318068224 | |
Created in thread: 123145354854400 | |
Created in thread: 123145307557888 | |
Created in thread: 123145344344064 | |
Created in thread: 123145328578560 | |
Created in thread: 123145312813056 | |
Created in thread: 123145323323392 | |
Created in thread: 123145339088896 | |
Created in thread: 123145333833728 | |
Created in thread: 123145344344064 | |
Created in thread: 123145318068224 | |
Created in thread: 123145354854400 | |
Created in thread: 123145307557888 | |
Created in thread: 123145328578560 | |
Created in thread: 123145323323392 | |
Created in thread: 123145312813056 | |
Created in thread: 123145349599232 | |
{<A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>, <A database>} | |
100 | |
Normal ============================================ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment