Как стать автором
Обновить
30
Карма
0
Рейтинг

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

  • Подписчики 41
  • Подписки 3

typeof(T) vs. TypeOf⟨T⟩

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


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

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

typeof(T) vs. TypeOf⟨T⟩

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

typeof(T) vs. TypeOf⟨T⟩

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


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


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(T) vs. TypeOf⟨T⟩

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


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

typeof(T) vs. TypeOf⟨T⟩

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


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

typeof(T) vs. TypeOf⟨T⟩

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


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


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


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

typeof(T) vs. TypeOf⟨T⟩

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


(: Шутка!

typeof(T) vs. TypeOf⟨T⟩

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


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

typeof(T) vs. TypeOf⟨T⟩

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

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


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


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


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


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

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


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

typeof(T) vs. TypeOf⟨T⟩

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

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

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

Мы же уже выяснили, что вы не делали анализа своих находок?
По моим личным критерия анализа, решения мне подходят. Вы свои критерии знаете куда лучше, поэтому применимость находок для себя сможете определить сами.

typeof(T) vs. TypeOf⟨T⟩

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

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

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

У меня нет цели доказывать кому-то что-то или навязывать. Нравится решение — бери и используй, не нравится — пробуй другое.

typeof(T) vs. TypeOf⟨T⟩

Так в чём проблема сделать
EqualityComparerProvider.GetDefault<T>()

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

typeof(T) vs. TypeOf⟨T⟩

Как я написал выше, оно хорошее в определённых дженерик случаях, где требуется высокая производительность.

typeof(T) vs. TypeOf⟨T⟩

Если бы совсем не в кэшировании и производительности, то можно было бы просто взять и на основе словаря, как у вас, сделать
EqualityComparer.GetDefault<T>()
.

typeof(T) vs. TypeOf⟨T⟩

Я вот вообще-то думал, что мы задачу про мемоизацию функции решаем.

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

typeof(T) vs. TypeOf⟨T⟩

Можете сделать RipeType дженериком (хотя это избыточно для конкретной задачи), а TypeOf⟨T⟩ переименовать в RipeType⟨T⟩ — получится та же картина, что и с EqualityComparer⟨T⟩.

typeof(T) vs. TypeOf⟨T⟩

В этой дискуссии, я писал про более общий паттерн кэширования при помощи статического дженерик класса, где частными случаями являются TypeOf⟨T⟩ и EqualityComparer⟨T⟩. Насколько понимаю, вы имели ввиду под «ужасным» кодом именно этот общий случай, который я схематически обозначил, и свою критику вы не детализировали.

Мне очень жаль, что вы не видете аналогии и не можете проследить общий паттерн.

typeof(T) vs. TypeOf⟨T⟩

Рефлексия — частный случай более общего сценария с оптимиацией.

typeof(T) vs. TypeOf⟨T⟩

Так а что ужасного в TypeOf⟨T⟩.GetSomething()?

Не нравится TypeOf⟨T⟩.GetSomething(), используйте эквивалентную форму TypeOf⟨T⟩.Ripe.GetSomething(), что аналогично EqualityComparer⟨T⟩.Default.Equals(a, b)

typeof(T) vs. TypeOf⟨T⟩

Самое дешёвое и универсальное решение (если только у вас не микроконтроллер с минимумом памяти) в случае использования множественных рефлексивных вызовов на основе typeof в различных частях приложения — это замена этой конструкции на статическую версию TypeOf (может быть, лишь за редким исключением на определённых CLR при получении полного типа).

И насчёт «ужасного кода» вот яркий пример
EqualityComparer<T>.Default.Equals(a, b);

Информация

В рейтинге
4,485-й
Зарегистрирован
Активность