Обратная совместимость
От: rameel https://github.com/rsdn/CodeJam
Дата: 16.10.18 13:16
Оценка:
Чтобы избежать лишних аллокации надо бы заменить в классе Fn<T> readonly поля на свойства, но сложность в обратной бинарной совместимости.

PS. Смысл в том, чтобы не инициализировать все поля за раз, так как ситуация, когда все свойства класса Operators<T> используются, исчезающе мала. Поэтому вместо того, чтобы инициализировать все и сразу, делаем лениво. Как то так:

Было:
private static readonly Lazy<Func<T, T>> _unaryMinus =
    new Lazy<Func<T, T>>(() => UnaryOperator<T>(ExpressionType.Negate), _lazyMode);

public static Func<T, T> UnaryMinus => _unaryMinus.Value;
...
И так все 25 свойств


Стало:
public static Func<T, T> UnaryMinus => UnaryMinusHelper.LazyValue.Value;

private static class UnaryMinusHelper
{
    public static readonly Lazy<Func<T, T>> LazyValue = new Lazy<Func<T, T>>(Factory, _lazyMode);
    private static Func<T, T> Factory() => UnaryOperator<T>(ExpressionType.Negate);
}


В этом случае, инициализированы будут только используемые свойства.

Так вот, такой трюк не проходит с классом Fn<T>, так как используются поля вместо свойств. Если совместимостью в этом случае можно пожертвовать, я поменяю поля на свойства, если нет — для класса Fn<T> верну как было.

Что думаете?
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re: Обратная совместимость
От: Sinix  
Дата: 16.10.18 16:29
Оценка:
Здравствуйте, rameel, Вы писали:

R>Чтобы избежать лишних аллокации надо бы заменить в классе Fn<T> readonly поля на свойства, но сложность в обратной бинарной совместимости.


Кмк, не имеет смысла. Мы сравниваем создание 1 Lazy vs создание ~25 Lazy при старте приложения. Я не думаю, что вызов нескольких конструкторов сильно влияет на перфоманс.
С точки зрения GC наоборот выгодно создавать долгоживущие объекты как можно раньше, чтобы не возиться при очистке gen0. Но это опять-таки копейки.

Бинарная совместимость не ломается, т.к. public api не меняется. Если кто лезет рефлексией — его проблемы.
Re[2]: Обратная совместимость
От: rameel https://github.com/rsdn/CodeJam
Дата: 17.10.18 12:45
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Кмк, не имеет смысла. Мы сравниваем создание 1 Lazy vs создание ~25 Lazy при старте приложения. Я не думаю, что вызов нескольких конструкторов сильно влияет на перфоманс.


Тут борьба больше не за тики, а за байты)

Да, только класс у нас generic, поэтому все это для каждого из используемых типов.

Нам коллеги репорт отписали, у них очень активно используются Fn<T>.SelfValue для разных типов и что-то из класса Operators, но лишнего плодится много, так вот в борьбе за байты, просили с оптимизировать этот момент, в точности, заменить на Method Group параметр lazy конструктора, так как Lazy за собой подчищает, но если пользоваться () => ..., то шарп кеширует в статической переменной до конца работы приложения, хотя по сути нужен всего раз. И того, у нас получается память выделилась на не используемые поля, на кеширование делегатов и так для каждого из задействованных типов.

ЗЫ. В нашем проекте разницы особо нет, так на уровне погрешности, но подумалось, если есть возможность немного урезать аппетит для случаев, когда используется для большого количества типов, то почему бы и нет, да и для GC работы в итоге меньше.

S>Бинарная совместимость не ломается, т.к. public api не меняется. Если кто лезет рефлексией — его проблемы.


Вроде же разный байткод используется для обращения к полю и свойству, нет?
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[3]: Обратная совместимость
От: Sinix  
Дата: 17.10.18 14:24
Оценка:
Здравствуйте, rameel, Вы писали:

R>Тут борьба больше не за тики, а за байты)

А есть какой-то пруфтест, который подтверждает эффект?

R>Нам коллеги репорт отписали, у них очень активно используются Fn<T>.SelfValue для разных типов и что-то из класса Operators, но лишнего плодится много, так вот в борьбе за байты, просили с оптимизировать этот момент, в точности, заменить на Method Group параметр lazy конструктора, так как Lazy за собой подчищает, но если пользоваться () => ..., то шарп кеширует в статической переменной до конца работы приложения, хотя по сути нужен всего раз. И того, у нас получается память выделилась на не используемые поля, на кеширование делегатов и так для каждого из задействованных типов


Ну вот с кейса и надо было начинать
Можешь детали подкинуть?
Подумаю вечером.

R>Вроде же разный байткод используется для обращения к полю и свойству, нет?

Поле наружу не выставляется, так что без разницы.
Re[4]: Обратная совместимость
От: rameel https://github.com/rsdn/CodeJam
Дата: 17.10.18 15:18
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Ну вот с кейса и надо было начинать

S>Можешь детали подкинуть?

Напишу ребятам, узнаю подробности.

Насколько я могу судить, смысл в том, что из такого кода:
public static class Sample<T>
{
    public readonly Lazy<int> Ten = new Lazy<int>(() => 10);
}


генерируется вот это:
public static class Sample<T>
{
    [Serializable]
    [CompilerGenerated]
    private sealed class <>c
    {
        public static readonly <>c <>9 = new <>c();
        public static Func<int> <>9__0_0;
        
        internal int <.cctor><>b__0_0()
        {
            return 10;
        }
    }
    
    public readonly Lazy<int> Ten = new Lazy<int>(<>c.<>9__0_0 ?? (<>c.<>9__0_0 = new Func<int>(<>c.<>9.<.cctor>b__0_0)));


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

Кстати, глянул IL, похоже сейчас рослин более смышленный, чем ранее. Для классов Fn<T>/Operators<T> шарп генерирует создание делегатов без кеширования (Студия VS2017 15.9 Preview 3).

S>Подумаю вечером.


Я для класса Operators уже внес изменения, описал в первом сообщении. Для каждого свойства завел отдельный внутренний класс, и при обращении к конкретному свойству, обращение делегируется в этот внутренний класс, остальные свойства не затрагиваются.

S>Поле наружу не выставляется, так что без разницы.


В классе Fn<T> у нас поля публичные.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[5]: Обратная совместимость
От: Sinix  
Дата: 17.10.18 20:13
Оценка:
Здравствуйте, rameel, Вы писали:

R>Напишу ребятам, узнаю подробности.

Да, давай. Я не против правок, главное чтоб от них измеримый эффект был.

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

Сейчас не так.

R>Кстати, глянул IL, похоже сейчас рослин более смышленный, чем ранее. Для классов Fn<T>/Operators<T> шарп генерирует создание делегатов без кеширования (Студия VS2017 15.9 Preview 3).

Давно так. С 7 емнип.

R>В классе Fn<T> у нас поля публичные.

Да, тут мы ССЗБ
Re: Обратная совместимость
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 24.10.18 11:50
Оценка:
Здравствуйте, rameel, Вы писали:

R>Чтобы избежать лишних аллокации надо бы заменить в классе Fn<T> readonly поля на свойства, но сложность в обратной бинарной совместимости.


ИМХО смысла в бинарной совместимости не особо много.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
AVK Blog
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.