Страницы

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

Показаны сообщения с ярлыком шаблон-одиночка. Показать все сообщения
Показаны сообщения с ярлыком шаблон-одиночка. Показать все сообщения

пятница, 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 сек.

понедельник, 23 декабря 2019 г.

Можно/нужно ли делать сервисы бизнес логики одиночками (Singleton) или статическими?

#c_sharp #net #архитектура #шаблон_одиночка


Например у меня есть сервисы ScannerService и UsersService. Первый отвечает за управление
сканером на устройстве, второй получает данные из базы данных и содержит в себе объект
DbContext (реализация UoW) для работы с базой данных. На разных формах используются
разные сервисы, но эти два почти на всех. Стоит ли создавать новые объекта в каждой
форме, или лучше использовать Singleton? 

Можно ли объект, реализующий Unit of work, делать Singleton? Он вроде должен быть
уничтожен после выполнения работы сервиса, в котором используется, но для меня не очевидно
зачем его создавать по сто раз для каждого сервиса, если можно создать один раз и уничтожить
после выполнения работы приложения.

Есть ли причины не делать сервисы статическими, если мне не нужно создавать их объекты,
а нужно лишь использовать их функции, которые можно сделать статическими?
    


Ответы

Ответ 1



Объект DbContext кэширует в себе все выбранные через него объекты (т.е. реализует не только Repository, UoW, но еще и Identity Map). Соответственно, если вы косвенно сделаете его синглтоном, то ваше приложение закэширует в себе все выбираемые через себя данные (всю базу) перестанет видеть изменения, вносимые в базу извне не сможет восстановиться после первой же ошибки валидации / сохранения (упал один SaveChanges - упадут и все следующие) будет дико тупить при сохранении из-за необходимости обнаруживать изменения в большом количестве объектов Нет никаких причин делать сервисы или вообще любые другие классы статическими, если того явно не требует логика работы конкретных классов. Т.е. статическим синглтоном может быть какой-то глобальный кэш, который по определению должен быть один на один инстанс приложения. Или, например, класс, оборачивающий в себе доступ к стороннему сервису, и управляющий соединениями к нему (пул соединений SQL, мультиплексор StackExchange Redis и т.п.). И даже в этом случае единственность экземпляра должен обеспечивать контейнер, а не прямая статика. Все остальное должно быть нестатическим, или, по крайней мере, не должно предполагать статичности/единственности зависимостей в своем коде.

суббота, 14 декабря 2019 г.

Никак не могу понять смысл использования singleton паттерна

#ооп #ruby #шаблон_одиночка


Много наслышан об паттерне программирования "singleton". Вот только никогда на практике
не приходилось встречать его в действии (а может и приходилось, но я об этом не догадываюсь).
Расскажите, что это такое (по русски, гуглом пользоваться умею, но кроме сухой терминологии
и пары non-real-life примеров ничего не находил), как, а главное в каких случаях им
можно/нужно пользоваться, ну и желательно пример (на Ruby, если можно).
    


Ответы

Ответ 1



Синглетон - это паттерн, описывающий объект в единственном экземпляре, без возможности создания его копии. Например, у вас имеются настройки для приложения и они должны быть в единственном экземпляре, не допускается создать копию такого объекта, изменить её в одной части приложения, а в другой станется не измененная старая копия. Или установив соединение с базой данных один раз, нужно воспользоваться уже установленным соединением и не создавать его повторно. Вместо базы данных, может быть лог-файл или любой другое хранилище существующее в единственном экземпляре. Для того, чтобы создать синглетон в Ruby вы должны закрыть возможность создания объекта через new и клонирование объекта (методы clone, dup, _dup). В стандартной библиотеки Ruby уже реализован модуль, подмешав который в собственный класс, вы можете превратить его в синглетон, включив его в класс. class MyClass include Singleton # ... end o = MyClass.instance

Ответ 2



Важно понимать, что в целом "паттерны ООП" -- это костыли, исторически возникающие для решения определенных проблем определенных языков программирования, т.е. не цель, а средство. Естественно, что во всех языках ООП разное, и например, Синглтон, как нечто особенное, не имеет острой необходимости в Руби вообще. Есть понятие "статическое поле (атрибут)" -- через него экземпляры класса могут общаться между собой или конфигурироваться извне все разом. Если вы подумаете об этом как об особом экземпляре, который есть изначально и он всегда один. вы можете захотеть его куда-то передать, но некоторые языки программирования не позволяют передавать класс в качестве аргументов функции -- принятым костылем для этой проблемы являлся Синглтон, но в Руби класс передавать можно. С остальным прекрасно справляются статические поля и методы класса, потому что на самом деле они являются обычными полями и методами метакласса -- неявного класса, который Руби создает для каждого явного, незаметно для пользователя инстанциируя его один раз, затем навешивая на него те методы, которые по вашему мнению висят на явно определенном классе, но "статически". Это по сути уже реализует Синглтон. Остальные выдумки, как например, модуль Singleton, существует в стандартной рубишной библиотеке лишь для того, чтоб люди, пришедшие из других языков программирования могли писать код визуально так, как привыкли, но не нужно "писать на языке А так, будто это Б" -- используйте инструмент правильно, обходитесь полями и методами класса. Примеры кода и еще немного объяснений про метаклассы: https://www.practicingruby.com/articles/ruby-and-the-singleton-pattern-dont-get-along https://stackoverflow.com/a/2505077/322020 https://rubymonk.com/learning/books/4-ruby-primer-ascent/chapters/39-ruby-s-object-model/lessons/131-singleton-methods-and-metaclasses

воскресенье, 1 декабря 2019 г.

Синглтон Майерса и многопоточность

#cpp #cpp11 #language_lawyer #шаблон_одиночка


Не раз слышал фразу:


  После c++11 синглтон Майерса стал потокобезопасным... 


Можете объяснить, почему такой код вдруг стал потокобезопасным?

class singleton
{
public:
    static singleton* instance() {
        static singleton inst;
        return &inst;
    }
private:
    singleton() {}
};

    


Ответы

Ответ 1



Это гарантируется стандартом, а именно [stmt.dcl]p4, стандарта C++17 (11 версии под рукой нет). Dynamic initialization of a block-scope variable with static storage duration (6.7.1) or thread storage duration (6.7.2) is performed the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization. If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined. Минусы подобного подхода мне не известны. Довольно удобный метод создания одиночки.

Что лучше использовать: синглтон или статический утилитарный класс?

#java #классы #static #шаблон_одиночка


Столкнулся с задачей, которую в равной степени можно решить двумя способами. Класс,
допустим DeviceState обращается к устройству десятки раз в секунду, поэтому каждый
раз создавать экземпляр не вариант.

Нужно использовать или синглтон или сделать класс статическим. И так и так работает.
Не могу определиться с выбором. По удобству, вроде как, статический выигрывает. Есть
ли какая-то разница по памяти и в быстродействии?

//singleton
DeviceState ds = ModbusMaster.getDeviceState(); //там происходит return DeviceState.getInstance(connParams);
System.out.println(ds.getLedState());

//full static        
DeviceState.refreshData();
System.out.println(DeviceState.ledState);

    


Ответы

Ответ 1



Думаю, в вашем случае лучше всё-таки использовать синглтон. Вот хорошая статья на эту тему: Если Ваш синглтон не поддерживает ни одного состояния, а просто обеспечивает доступ к методам, лучше рассмотреть использование статического класса, так как статические методы гораздо быстрее синглтона, благодаря статичному связыванию во время компиляции. Если по Вашим требованиям необходимо поддержать состояние, то в таком случае синглтон является лучшим выбором, чем статический класс, потому что поддержание состояния в последнем случае — кошмар, и ведет к неочевидным ошибкам. А так как у вас сам класс называется DeviceState, думаю, он должен поддерживать разные состояния, значит, нужен синглтон. Что касается производительности: Статический класс предоставляет большую производительность, чем синглтон, потому что статические методы связываются во время компиляции. Но думаю, что особенной разницы в производительности вы не заметите, а стилистически правильнее будет использовать синглтон.

Ответ 2



По производительности и памяти в вашем случае статика не будет отличаться от синглтона. Имеет смысл использовать именно второй подход (Singletone) т.к. это даст вам возможность в дальнейшем использовать преимущества полиморфизма. В тестовом окружении например можно будет заменить имплементацию DeviceState на "заглушку" с необходимой для теста логикой, либо менять реализацию в зависимости от типа устройства с которым общается DeviceState.

Ответ 3



Не думайте, как быстрее (до того, как вы провели профилирование), думайте, как правильно. Статический метод в DeviceState означает, что метод относится ко всем возможным DeviceState. Синглтон означает, что у вас есть ровно один DeviceState, и ваши вызываемые методы относятся в точности к нему. В вашем случае у вас именно второй вариант: у вас одно устройство. Вот и используйте синглтон. Вы не должны задаваться вопросом «как быстрее». Если писать всё «как быстрее», то не нужны ни классы, ни методы, а лишь один большой метод с goto. Улучшать производительность заранее не имеет смысла, «преждевременная оптимизация — источник всех бед». Ну и несчастная сотня вызовов в секунду — это так мало, что разницу в скорости не заметит никто.

суббота, 15 июня 2019 г.

Статический конструктор структуры и инициализация синглтона

Вопрос на основе двух статей:
О синглтонах и статических конструкторах Реализация синглтонов в .NET: Field-like vs. Lazy
Собственно, вспомнил, что у структур несколько иначе обстоят дела с вызовом статического конструктора (он вызывается перед обращением к статическому полю, но не вызывается при создании инстанса структуры). Соответственно, возникло желание поместить свойство Instance внутрь структуры. Сначала я хотел что-то намудрить с красотой обращения к нему, но потом передумал и решил спросить по самому концепту - даёт ли это что-то помимо ленивой инициализации (кстати, а действительно ли она тут гарантирована) и есть ли какие-то побочные эффекты?.
http://ideone.com/BrgjAI
using System;
struct FieldLikeSingletonWrapper { public class FieldLikeSingleton { internal FieldLikeSingleton() { Console.WriteLine("FieldLikeSingleton.ctor"); }
public void Foo() { Console.WriteLine("Foo"); } }
public static FieldLikeSingleton Instance { get; } = new FieldLikeSingleton(); }
class Program { static void Main(string[] args) { Console.WriteLine("Inside Main()");
if (args.Length == 42) { FieldLikeSingletonWrapper.Instance.Foo(); } } }
Кстати, сначала мне казалось очевидным, что сделать сам синглтон структурой - идея ужасная, поскольку структура будет копироваться. Но потом я подумал, что можно объявить прокинуть методы через структуру (да, это минус), но использовать скрытый вложенный класс:
http://ideone.com/Ok1XP0
using System;
struct FieldLikeSingleton { private class FieldLikeSingletonImpl { internal FieldLikeSingletonImpl() { Console.WriteLine("FieldLikeSingleton.ctor"); }
public void Foo() { Console.WriteLine("Foo"); } }
private static FieldLikeSingletonImpl instance = new FieldLikeSingletonImpl(); public static FieldLikeSingleton Instance { get; }
public void Foo() { instance.Foo(); } }
class Program { static void Main(string[] args) { Console.WriteLine("Inside Main()");
if (args.Length == 42) { FieldLikeSingleton.Instance.Foo(); } } }
Какие плюсы и минусы есть у этих подходов по сравнению с обычным field-like?


Ответ

вспомнил, что у структур несколько иначе обстоят дела с вызовом статического конструктора (он вызывается перед обращением к статическому полю, но не вызывается при создании инстанса структуры).
Это не совсем так. Точнее, это так, если считать, что default(T) - это единственный способ создания экземпляра структуры. Да, в случае var x = new FooStruct() статический конструктор не вызывается, поскольку в этом случае происходит просто выделение и обнуление блока памяти. Если бы в этом случае была проверка инициализации типа, то это привело бы к существенным накладным расходам во время исполнения (а ведь структуры предназначены именно для таких low-level сценариев, где каждый такт имеет значение).
Аналогично, при копировании структуры статический конструктор не будет вызван:
var @default = new FooStruct(); // нет вызова статического конструктора var copy = @default; // нет вызова статического конструктора
Однако при вызове пользовательского конструктора структуры, статический конструктор будет вызван (это же будет справедливым и для пользовательского конструктора по-умолчанию; его нельзя создать в C#, но если создадите, то статический конструктор будет вызываться и для var x = new FooStruct()):
var instance = new FooStruct(42);
Вообще, тут нужно понять, какую именно проблему вы хотите решить.
Если вопрос с ленивостью инициализации синглтона, то наличие поля Instance во вложенном классе сделает поведение полностью ленивым:
class SomeSingleton { private class SingletonHolder { public static readonly SomeSingleton Instance = new SomeSingleton(); }
public static SomeSingleton Instance => SingletonHolder.Instance; }
В этом случае обращение к статическим членам класса SomeSingleton не приведет к инициализации синглтона. Единственный способ инициализации синглтона - обращение к свойству Instance
Подчеркну: это решение полностью ленивое, но оно страдает остальными проблемами field-like синглтонов, связанных с исключениями.
P.S. Ну и все танцы с бубном по делегированию структуре - вещь просто избыточная: она серьезно усложняет сопровождение без каких-либо выгод с точки зрения времени исполнения.

понедельник, 19 ноября 2018 г.

Можно/нужно ли делать сервисы бизнес логики одиночками (Singleton) или статическими?

Например у меня есть сервисы ScannerService и UsersService. Первый отвечает за управление сканером на устройстве, второй получает данные из базы данных и содержит в себе объект DbContext (реализация UoW) для работы с базой данных. На разных формах используются разные сервисы, но эти два почти на всех. Стоит ли создавать новые объекта в каждой форме, или лучше использовать Singleton?
Можно ли объект, реализующий Unit of work, делать Singleton? Он вроде должен быть уничтожен после выполнения работы сервиса, в котором используется, но для меня не очевидно зачем его создавать по сто раз для каждого сервиса, если можно создать один раз и уничтожить после выполнения работы приложения.
Есть ли причины не делать сервисы статическими, если мне не нужно создавать их объекты, а нужно лишь использовать их функции, которые можно сделать статическими?


Ответ

Объект DbContext кэширует в себе все выбранные через него объекты (т.е. реализует не только Repository, UoW, но еще и Identity Map).
Соответственно, если вы косвенно сделаете его синглтоном, то ваше приложение
закэширует в себе все выбираемые через себя данные (всю базу) перестанет видеть изменения, вносимые в базу извне не сможет восстановиться после первой же ошибки валидации / сохранения (упал один SaveChanges - упадут и все следующие) будет дико тупить при сохранении из-за необходимости обнаруживать изменения в большом количестве объектов
Нет никаких причин делать сервисы или вообще любые другие классы статическими, если того явно не требует логика работы конкретных классов. Т.е. статическим синглтоном может быть какой-то глобальный кэш, который по определению должен быть один на один инстанс приложения. Или, например, класс, оборачивающий в себе доступ к стороннему сервису, и управляющий соединениями к нему (пул соединений SQL, мультиплексор StackExchange Redis и т.п.). И даже в этом случае единственность экземпляра должен обеспечивать контейнер, а не прямая статика.
Все остальное должно быть нестатическим, или, по крайней мере, не должно предполагать статичности/единственности зависимостей в своем коде.

суббота, 20 октября 2018 г.

Никак не могу понять смысл использования singleton паттерна

Много наслышан об паттерне программирования "singleton". Вот только никогда на практике не приходилось встречать его в действии (а может и приходилось, но я об этом не догадываюсь). Расскажите, что это такое (по русски, гуглом пользоваться умею, но кроме сухой терминологии и пары non-real-life примеров ничего не находил), как, а главное в каких случаях им можно/нужно пользоваться, ну и желательно пример (на Ruby, если можно).


Ответ

Синглетон - это паттерн, описывающий объект в единственном экземпляре, без возможности создания его копии. Например, у вас имеются настройки для приложения и они должны быть в единственном экземпляре, не допускается создать копию такого объекта, изменить её в одной части приложения, а в другой станется не измененная старая копия. Или установив соединение с базой данных один раз, нужно воспользоваться уже установленным соединением и не создавать его повторно. Вместо базы данных, может быть лог-файл или любой другое хранилище существующее в единственном экземпляре.
Для того, чтобы создать синглетон в Ruby вы должны закрыть возможность создания объекта через new и клонирование объекта (методы clone, dup, _dup). В стандартной библиотеки Ruby уже реализован модуль, подмешав который в собственный класс, вы можете превратить его в синглетон, включив его в класс.
class MyClass include Singleton # ... end
o = MyClass.instance

пятница, 5 октября 2018 г.

Синглтон Майерса и многопоточность

Не раз слышал фразу:
После c++11 синглтон Майерса стал потокобезопасным...
Можете объяснить, почему такой код вдруг стал потокобезопасным?
class singleton { public: static singleton* instance() { static singleton inst; return &inst; } private: singleton() {} };


Ответ

Это гарантируется стандартом, а именно [stmt.dcl]p4, стандарта C++17 (11 версии под рукой нет).
Dynamic initialization of a block-scope variable with static storage duration (6.7.1) or thread storage duration (6.7.2) is performed the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization. If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined.
Минусы подобного подхода мне не известны. Довольно удобный метод создания одиночки.