#python #шаблоны_проектирования #singleton #шаблон_одиночка
Здравствуйте! Подскажите, пожалуйста относительно моей реализации одиночки. Реализую как рекомендуют pep-0318: Итого, получается код, вида: def singleton(cls): instance = {} def get_instance(): if cls not in instance: instance[cls] = cls() return instance[cls] return get_instance() @singleton class MyClass: ****** Я никак не могу понять, почему работает мой код. Я экспериментировал с 10 потоками, которые вызывают один и тот же метод этого класса, метод отрабатывает по времени долго (4-5 сек. реального времени), но блокировок вызвать не получилось. Данная реализация является потокобезопасной? Если да, то почему?
Ответы
Ответ 1
В CPython (стандартный интерпретатор Python) используется GIL. Из-за него потоки в Python работают не параллельно (за исключением потоков ввода вывода), а по очереди (кооперативно). Когда один поток запускается GIL блокирует все остальные. Более подробно о GIL wiki, habr Дополнение: Сама реализация сингл тона (без доп. блокировок в методах) не является потоко-безопасной Прим: @singleton class MyClass: def __init__(self, a): self.a = a def sum(self, arr): for val in arr: self.a += val def mrange( limit ): for i in range( limit ): yield i if i % 100 == 0: time.sleep(0.000001) if __name__ == '__main__': obj = MyClass(0) start = time.time() threads_num = 2 range_lenth = 100000 threads = [] for i in range( threads_num ): data = range( range_lenth ) #data = mrange( range_lenth ) t = threading.Thread(target=obj.sum, args=(data,)) t.start() threads.append(t) for thr in threads: thr.join() print(obj.a) print('Программа отработала за:',time.time() - start) При использовании стандартного range программа может выдавать разный результат, т.к. прерывание иногда может происходить внутри операции += % python threads.py 9999900000 Программа отработала за: 0.024893522262573242 % python threads.py 8426007253 Программа отработала за: 0.02556920051574707 % python threads.py 6761264079 Программа отработала за: 0.02519679069519043 Но если по какой-либо причине, внутри метода синглтона, будет происходить прерывание чаще чем требует GIL то результат будет стабилен и верен. (Если раскомментировать data = mrange). % python threads.py 9999900000 Программа отработала за: 0.10795187950134277 % python threads.py 9999900000 Программа отработала за: 0.08879899978637695 % python threads.py 9999900000 Программа отработала за: 0.10483145713806152Ответ 2
Если я правильно вопрос понял import threading, time def singleton(cls): instance = None def inner(*args, **kwargs): nonlocal instance if instance is None: instance = cls(*args, **kwargs) return instance return inner @singleton class MyClass: def __init__(self, a, b): self.a = a self.b = b def add(self): self.a += 1 self.b += 1 if __name__ == '__main__': obj = MyClass(1, 2) obj1 = MyClass(3, 4) print(obj == obj1) start = time.time() threads = [] for i in range(10): t = threading.Thread(target=obj.add) t.start() threads.append(t) for thr in threads: thr.join() print(obj.a, obj.b) print('Программа отработала за:',time.time() - start) # 0.002 сек.
Комментариев нет:
Отправить комментарий