Страницы

Поиск по вопросам

пятница, 24 января 2020 г.

Потокобезопасная реализация одиночки

#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 сек.

Комментариев нет:

Отправить комментарий