Минутка WTF-10: посчитай их правильно.
От: Sinix  
Дата: 15.09.16 06:17
Оценка: 49 (5)
Что-то подзабросил я серию
Автор: Sinix
Дата: 10.05.16
. Исправляем
Спонсор сегодняшнего поста — stackoverflow (спойлеры по ссылке).

  код
    static class Program
    {
        struct ValueHolder
        {
            private readonly long _value;

            public ValueHolder(long value)
            {
                _value = value;
            }
        }
        struct ValueHolderNullable
        {
            private readonly long? _value;

            public ValueHolderNullable(long? value)
            {
                _value = value;
            }
        }
        
        static void Main(string[] args)
        {
            Console.WindowWidth = 120;

            var data = Enumerable.Range(0, 10000)
                .Select(i => (long)i % 1000)
                .ToArray();

            var data2 = data.Select(l => new ValueHolder(l)).ToArray();

            var data3 = data.Select(l => new ValueHolderNullable(l)).ToArray();

            // Замеры начались
            Measure("Raw", () =>
            {
                data.Distinct().ToArray();
                return data.Length;
            });

            Measure("Wrapper", () =>
            {
                data2.Distinct().ToArray();
                return data2.Length;
            });

            Measure("NullableWrapper", () =>
            {
                data3.Distinct().ToArray();
                return data3.Length;
            });
            // Замеры закончились

            Console.WriteLine("Done.");
            Console.ReadKey();
        }

        static void Measure(string name, Func<long> callback)
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            var mem = GC.GetTotalMemory(true);
            var gc00 = GC.CollectionCount(0);
            var gc01 = GC.CollectionCount(1);
            var gc02 = GC.CollectionCount(2);

            var sw = Stopwatch.StartNew();
            var result = callback();
            sw.Stop();

            var mem2 = GC.GetTotalMemory(false);
            var gc10 = GC.CollectionCount(0);
            var gc11 = GC.CollectionCount(1);
            var gc12 = GC.CollectionCount(2);

            var memDelta = (mem2 - mem) / 1024.0;
            var gcDelta0 = gc10 - gc00;
            var gcDelta1 = gc11 - gc01;
            var gcDelta2 = gc12 - gc02;

            Console.WriteLine(
                "{0,20}: {1,5}ms, ips: {2,22:N} | Mem: {3,9:N2} kb, GC 0/1/2: {4}/{5}/{6} => {7,6}",
                name, sw.ElapsedMilliseconds, result / sw.Elapsed.TotalSeconds, memDelta, gcDelta0, gcDelta1, gcDelta2, result);
        }
    }


  вывод (для нетерпеливых)
                 Raw:     2ms, ips:           3 674 849,33 | Mem:     84,02 kb, GC 0/1/2: 0/0/0 =>  10000
             Wrapper:     5ms, ips:           1 958 288,46 | Mem:    519,83 kb, GC 0/1/2: 0/0/0 =>  10000
     NullableWrapper:  2759ms, ips:               3 623,46 | Mem:    655,90 kb, GC 0/1/2: 229/0/0 =>  10000
Done.


Вопрос обычный: как так-то?
Отредактировано 07.01.2017 16:45 Sinix . Предыдущая версия .
минутка wtf
Re: Минутка WTF-10: посчитай их правильно.
От: Lexey Россия  
Дата: 16.09.16 14:32
Оценка: 69 (1) +1
Здравствуйте, Sinix, Вы писали:

S>Вопрос обычный: как так-то?


Привет дефолтовому компареру? Если Equals и GetHashCode переопределить, то все сразу становится хорошо.

Upd: почитал тред на SO. Веселуха, однако.
Получается, что дефолтовая реализация GetHashCode забивает на реализацию в Nullable<T> и считает все по своему.
Это реально WTF.
"Будь достоин победы" (c) 8th Wizard's rule.
Отредактировано 16.09.2016 14:45 Lexey . Предыдущая версия .
Re[2]: Минутка WTF-10: посчитай их правильно.
От: Sinix  
Дата: 16.09.16 14:52
Оценка: 5 (1) +4
Здравствуйте, Lexey, Вы писали:

L>Это реально WTF.

Ну вот таки да.

Всё больше и больше убеждаюсь, что товарищи, которые ленятся включить "CA1815: Override equals and operator equals on value types" — ССЗБ.
Отредактировано 16.09.2016 14:53 Sinix . Предыдущая версия .
Re[3]: Минутка WTF-10: посчитай их правильно.
От: hardcase Пират http://nemerle.org
Дата: 16.09.16 19:15
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Всё больше и больше убеждаюсь, что товарищи, которые ленятся включить "CA1815: Override equals and operator equals on value types" — ССЗБ.


Вот только не все структуры предназначены для использования в виде ключей. Я обычно поступаю от использования: как только необходимо структуру пихнуть в Set или Dictionary, выясняю реализует ли она IEquatable.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[4]: Минутка WTF-10: посчитай их правильно.
От: Sinix  
Дата: 16.09.16 19:53
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Вот только не все структуры предназначены для использования в виде ключей. Я обычно поступаю от использования: как только необходимо структуру пихнуть в Set или Dictionary, выясняю реализует ли она IEquatable.

+1. Но это справедливо для непубличных типов. Для public-структур лучше подстраховаться. Спасиб что напомнили, сейчас подарю ещё парочку WTF
Автор: Sinix
Дата: 16.09.16
.
Отредактировано 16.09.2016 20:18 Sinix . Предыдущая версия . Еще …
Отредактировано 16.09.2016 20:17 Sinix . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.