Pull to refresh
57
0

Пользователь

Send message
Считайте всё это, чем захотите, я вам уже приводил своё определение паттерна раньше, и оно расходится с вашим, насколько мы выяснили. Поэтому нет ничего удивительного, что наши мнения снова отличаются.
На этом ваша аналогия и развалилась. Конкретная реализация паттерна не является паттерном.

Ничего не развалилось. Печально, если вы не улавливаете аналогию и не в состоянии ответить на последующие вопросы. Я сделал всё, что мог.
Я поправил
«Шарик — это собака (вид животных)»
на
«Шарик — это собака (животное)»

Чтобы было очевиднее, что
«Шарик — это животное»
«TypeOf⟨T⟩ — это паттерн»

Основной акцент в публикации делаю на TypeOf⟨T⟩, потому что дошёл до чёткого понимания этого паттерна лишь году на седьмом активного пользования дженериками. На мой взгляд, такое решение далеко не очевиденое, хотя довольно простое в своей основе.

Мемоизация или не мемоизация происходит в RipeType я не знаю, но кэширование точно есть и на новизну вовсе не претендую, основная цель была в проведении сравнительных бенчмарков.
Уже объяснял, но… TypeOf⟨T⟩ — конкретная реализация паттерна кэширования (мемоизации) через статический дженерик класс (назовём паттерн для дальнейшего примера Static Generic Memorization [SGM]), RipeType — через словарь (Dictionary Memorization [DM]).

Ровно так же, как StringBuilder — конкретная реализация паттерна Builder.

Рассмотрим простую аналогию. Названия видов животных (собака, кошка, бегемот, слон, дельфин...) соответствуют видам паттернам (SGM, DM, фабрика, билдер...). Конкретные реализации, например, Шарик и Мурка соответствуют конкретным реализациям TypeOf⟨T⟩ и RipeType.

Вместе с тем Шарик, являясь конкретной реализацией, не перестаёт быть собакой, как TypeOf⟨T⟩ не перестаёт быть реализацией паттена SGM.

Утверждения
«Шарик — это собака (животное)» являются истинными
«TypeOf⟨T⟩ — это SGM (паттерн)» тоже истинны.

Понятнее теперь?
можно его и под что-то еще адаптировать.
Именно. TypeOf, RipeType — конкретные случаи.

В первую очередь код ориентирован на десктопные и мобильные приложения.

Содержит, потому что я художник и так вижу.


А если серьёзно, каждый может по-своему откорректировать реализацию для продакшена, если потребуется, в публикации я только делюсь идеей (паттерном), а не идеальной имплементацией на все случаи жизни.

Да. А зачем вам описания?


  1. Clone All
  2. Find All по TypeOf

Конечно, зесь вам самим решать, тратить на это время или нет.

Как бы и разворачивает, но


применение явных статических конструкторов приводит к генерации менее производительного кода.

https://msdn.microsoft.com/ru-ru/library/dd335949.aspx

Все мои случаи доступны в открытых репозиториях с кодом — изучайте при желании.

Из рубрики "Вредные советы" любителям антипаттернов


Использовать с осторожностью! Автор ответствености не несёт! :)


Global Lock
using System;

namespace Ace.Sugar
{
    public static class Lock<TResult>
    {
        public static readonly object GlobalSyncContext = new object();
    }

    public static class Lock
    {
        public static readonly object GlobalSyncContext = new object();

        public static void Invoke(Action action)
        {
            lock (GlobalSyncContext) action();
        }

        public static void Invoke<TSyncContext>(TSyncContext customSyncContext, Action<TSyncContext> action)
        {
            lock (customSyncContext) action(customSyncContext);
        }

        public static TResult Invoke<TResult>(Func<TResult> func)
        {
            lock (Lock<TResult>.GlobalSyncContext) return func();
        }

        public static TResult Invoke<TSyncContext, TResult>(TSyncContext customSyncContext, Func<TSyncContext, TResult> func)
        {
            lock (customSyncContext) return func(customSyncContext);
        }
    }
}

Минусы:


  • повышенная вероятность взаимной блокировки при использовании GlobalSyncContext
  • дополнительное выделение памяти при использовании лямбда выражений
  • плохая производительность в многопоточной среде

Плюсы:


  • не обязательно явно вводить новую переменную, позволяет ограничиваться однострочным кодом и использовать любимые лямбдочки везде и всюду, избегая ненавистных скобок { } в методах
  • не годится для продакшена, но для приложений на коленке сойдёт

Lock.Invoke(() => DoSomething());
Lock.Invoke(customSyncContext, c => DoSomething());

Да, везде заменил, потому что медленнее работать не будет в моих случаях, плюс общность появляется, а не где-то typeof, а где-то TypeOf.


А плата в виде слегка повышенное потребления памяти вполне для меня допустима.

Варианты оптимизаций я рассматриваю для каждого случая индивидуально. Касательно typeof у меня был ряд сценариев, где его избежать нельзя. Судя по результатам бенчмарков в терминах скорости выполнения, использование TypeOf в большинстве случаев даёт ощутимый выигрыш.


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

Иногда по определённым вопросам спор с вами напоминает мне парадокс Кэррола.


Перед вами очевидные суждения:
А. чем меньше времени занимает событие, тем оно быстрее происходит
Б. определённые вызовы сравниваемых методов занимают меньше времени, чем другие


В. значит, эти вызовы быстрее


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

Для таких случаев есть служба поддержки в платёжной системе.


(: Шутка!

Да, текущая имплементация не лишена недостатков, но поскольку бенчмарки уже проведены на ней, в тексте публикации оставил её как есть, но добавил соответствующее примечание.


Думаю, каждый сможет адаптировать её под свои конкретные требования, чтобы достичь оптимальной производительности.

Короче, если в TypeOf<> на core избавиться от статического конструктора

Для меня это было сюрпризом, но инициализация статических полей выполняется вне/без статического конструктора.


Добавление явного статического конструктора в текущей имплементации TypeOf влияет на скорость доступа к статическим рид-онли полям, причём, есть зависимость от типа дженерик параметра — ссылочный он или нет. На CLR замедляет TypeOf⟨int⟩ и TypeOf⟨string⟩, но на Core ускоряет TypeOf⟨int⟩, оставляя производительность TypeOf⟨string⟩ на прежнем уровне.


Разница обусловлена кодом, генерируемым JIT-компилятором. В медленнных случаях при доступе к статическому рид-онли полю вставляется дополнительная инструкция для проверки того факта, проинициализировано оно уже или нет.


Вообще это связано с следующими вопросами:


  • Что выполняется раньше, инициализация полей либо статический конструктор?
  • Как гарантировать потокобезопасные инициализацию полей и вызов статического конструктора?

Сейчас в различных средах исполнения имеются свои тонкости в реализации этих механизмов.


Вашу оптимизацию можно использовать, если, к примеру, гарантировано вызывать TypeOf⟨A⟩.Init(), TypeOf⟨B⟩.Init()… при старте приложения, пока не создались другие потоки, использующие кэшированные данные. Поскольку вызовы одиночные большого проседания в скорости запуска приложения это не вызовет (можно также такие инициализации вынести в отдельный поток). К сожалению, это вносит неудобства в использование, но зато даёт дополнительный выигрыш в производительности для критичных случаев.

Что касается typeof, то в своих вольных проектах я везде заменил его на TypeOf, потому что для меня это самое оптимальное и универсальное решение для улучшения производительности.

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

Теперь осталось выяснить, не было ли лучшего способа решить вашу проблему.
К сожалению, способа получения информацию о типе минуя typeof или GetType я не знаю, но знаю, как её закэшировать для наиболее быстрого доступа в дальнейшем.

Мы же уже выяснили, что вы не делали анализа своих находок?
По моим личным критерия анализа, решения мне подходят. Вы свои критерии знаете куда лучше, поэтому применимость находок для себя сможете определить сами.
Как вам объяснить… Где я написал, что так нужно делать везде и всегда? Если вас устраивает вариант со словарём, то, пожалуйста, пользуйтесь!

В своей практике я дошёл до того момента, когда мне потребоволась кэшировать информацию о типах, чтобы достичь лушей производительности, и TypeOf с RipeType мне в этом помогли.

Дальше я просто поделился опытом с другими людьми, потому что до этих решений дошёл далеко не сразу, пришлось проводить различные замеры, эксперементировать с реализациями, разбираться с деталями. И своей статьёй, возможно, кому-то сохраню немало времени в дальнейшем.

У меня нет цели доказывать кому-то что-то или навязывать. Нравится решение — бери и используй, не нравится — пробуй другое.
Так в чём проблема сделать
EqualityComparerProvider.GetDefault<T>()

со словарём внутри, который предоставляет инстенсы EqualityComparer⟨T⟩? Почему выбрано иное решение?

Information

Rating
Does not participate
Registered
Activity