All streams
Search
Write a publication
Pull to refresh
6
0.2

Разработчик

Send message
Для тяжелых компонентов — синглтон практически единственный сценарий использования. Для всего остального ничто не мешает использовать IoC классически.
Естественно, если время старта устраивает, смысла нет. Я все это и затеял, когда суммарное время обновления нод (они обновляются по очереди) перевалило за час.
Это хороший подход, мне уже говорили некоторые коллеги, что он более правилен архитектурно. Но он и рассчитан на более хорошую кодовую базу, которая имеется не всегда. Зачастую имеется куча кода (например легаси), который, в общем, не знает об асинхронности, потому что писался 5 лет назад, у которого вся инициализация в конструкторе, который выполняется секунд эдак 30, причем в качестве параметра ему предварительно надо вычислить текущую фазу луны. К нему надо писать дополнительный слой абстракции. Это всё, конечно, крайние случаи, но они показывают что в моем коде разобраться будет, в общем, проще, т.к. вся инициализация от создания до регистрации в контейнере — в одном месте.

Кроме того, непроинициализированный компонент в IoC-контейнере — потенциально опасное место.
Я так изначально и задумывал. Но вышло весьма «корявенько». Поэтому оставил вариант с синхронизацией.
отсутствие выигрыша при параллельном запуске легко может объясняться, например, тем, что у вас все обращения идут к одной БД, и она не справляется
Если асинхронная инициализация отрицательно влияет на производительность, никто ведь не мешает часть компонентов проинициализировать по классической, синхронной схеме. Еще в рамках тюнинга конкретной ситуации можно внутри задачи someTask в самом начале явно прописать await someOtherTask — заставляя someOtherTask завершится до инициализации someTask, что в вашем случае положительно повлияет на производительность.

Я старался решить проблему ускорения загрузки приложений «в общем». Но вышло это ценой расположения регистраций по-порядку в коде (почему многие считают, что это минус?) и регистрации готовых инициализированных инстансов вместо типов (что в моем случае явный плюс, но тоже многие коллеги не согласны).
Как я упоминал в самом начале, для моих задач (бекенд за балансировщиком) мне выгоднее провести инициализацию всего тяжелого именно на старте. Я не хочу увеличивать время отклика первых пришедших пользователей. Поэтому стараюсь на старте загрузить по-максимуму, а отложенную инициализацию использую очень осторожно.
Это также помогает диагностике. Потому что приложение в случае проблем упадет прямо здесь и сейчас в момент запуска, когда администратор занят непосредственно запуском. А не через несколько часов, когда кто-то из клиентов вызовет крайне редкоиспользуемый метод.

Наверное, следовало все-таки вынести в статью, почему я предпочитаю явную инициализацию экземпляров вместо регистрации типов.
Главная причина — это понятность и читаемость кода. Когда открываешь сравнительно простой чужой проект с точки зрения бизнес-логики и видишь в инициализации IoC-контейнера адскую мешанину из многоэтажных конструкций RegisterType, Resolve и InjectionConstructor, то… тоска и желание закрыть это и больше никогда не открывать. Очень тяжело разобраться сходу какая реализация интерфейса будет использоваться в качестве зависимости (реализаций часто несколько), какой конструктор вызван и т.д. Совсем другое дело, когда зависимости компонентов прописаны явно, а не «размазаны» по коду.

Несомненно, бывают случаи, когда нам нужен каждый раз новый экземпляр компонента. Я в этом случае предпочитаю регистрировать фабрику компонентов (как инстанс) с кастомной логикой (которую всё-равно писать вручную), и использовать получение компонента через эту фабрику.

В случае необходимости отложенной инициализации (как я уже упоминал, для моих задач это редкость) можно попробовать использовать Lazy<>, причем в функторе инициализации придется использовать heavyComponentXTask.Result вместо await heavyComponentXTask

Потокобезопасность при инициализацией экземпляров компонентов в общем не должна нас волновать, т.к. у нас регистрируется либо единственный экземпляр либо фабрика, которая при необходимости возьмет задачи по синхронизации контекста на себя.

В случае, если операции инициализации не приносят выигрыша при параллельном запуске (видимо инициализация происходит практически мгновенно), то инициализация не принесет и значительного проигрыша. Пара миллисекунд на создание обертки в виде задачи над инициализацией компонента — это совсем небольшой оверхед.

А с зависимостями, усложняющими граф самое вкусное. Достаточно описать задачу инициализации зависимости выше по коду чем задачи, где эта зависимость упоминается. Дальше задачи выстроятся в очередь планировщиком за счет использования await «автоматически».
Циклические зависимости компонентов друг от друга я не рассматриваю, т.к. это явные архитектурные проблемы.
12 ...
21

Information

Rating
2,732-nd
Location
Cary, North Carolina, США
Registered
Activity