Pull to refresh

Comments 11

Согласен, что ёмкость коллекции нужно задавать, когда она заранее известна, но в данном конкретном примере гораздо проще использовать такой код:
Код
static void Main(string[] args)
        {
            var firstList = new List<string>(args);

            var secondList = new List<string>();
            secondList.AddRange(args);
        }


Хоть конструктор и принимает IEnumerable, но внутри будет каст к ICollection, затем проверка размера с выделением массива этого размера и вызов метода CopyTo.
AddRange работает аналогично, сначала при необходимости увеличивает размер до нужного, а затем копирует элементы из исходной коллекции. Удобен если в коллекции элементы уже есть.

p.s. Оба варианта не приводят к лишним аллокациям, а код выглядит приятнее в отличии от ручного копирования.
p.p.s. Актуально для .Net 5, .Net Core и .Net Framework

Ну, не совсем. Мы же не берём исходную коллекцию "as is", а изменяем её - для каждого элемента вызывается Clone. То есть просто указать её в конструкторе или передать в AddRange не выйдет. LINQ с Select сюда тоже добавлять не хотелось понятно по каким причинам. :)

Забыл про Clone. Теперь полностью согласен :)
Отличная работа. Особенно порадовал результат экспериментов с GC, т.к. я ожидал немного меньшего результата :)

Спасибо! Нас тоже очень порадовал. :)

Отличная статья, рассматривались ли варианты вроде NetFabric.Hyperlinq или StructLinq, что-бы максимально сохранить простоту LINQ и не переписывать всё на циклы?

Отличная статья

Спасибо!

рассматривались ли варианты вроде NetFabric.Hyperlinq или StructLinq, что-бы максимально сохранить простоту LINQ и не переписывать всё на циклы

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

В общем и целом LINQ по коду осталось много, просто теперь у нас есть лучшее понимание того, где его можно использовать достаточно спокойно, а где лучше подумать или сразу воздержаться. :)

UFO just landed and posted this here

Насчет Count (и Any) загляните в исходники LINQ - он достаточно хитер и если видит что IEnumerable это на самом деле List или Array то вызовет их свойства Count и Length напрямую.

Безпредикатная версия Count - да, я как раз приводил имплементацию в статье. В Any такого нет. Ссылка на referencesource. В .NET завезли, похоже. Ссылка.

Неужели чтобы догадаться что params передается как массив необходимо было дизассемблировать в IL? Да он же в сигнатуре даже объявлен как массив.

Люблю в IL лазить, чтобы прояснять для себя разные моменты. Например, про передачу явного null (что он не заворачивается), на оптимизации вызовов без аргументов тоже было интересно посмотреть. Про атрибут не знал. Да и в общем, думаю, кому-то может быть интересно, что там под капотом.

collection.Where(predicate).Skip(12).Any()

Лично мне не очень нравится читаемость этого кода (может просто не привык) + создание итераторов.

Например, про передачу явного null (что он не заворачивается)

Попробуйте передать (string)null будет опять создаваться массив

Немного неочевидное поведение, но просто нул считается как уже массив

Что произошло при вызове метода с params? Выделил память (инкремент счётчика), заполнили, использовали и забыли. Далее GC (внимание) проходит по живым, достижимым объектам, среди которых нашего params массива уже нет. GC компактит кучу и перетирает память выделенную под params так никогда и не узнав, что он вообще существовал.

То есть непонятно зачем вы оптимизировали временные объекты если их создание и удаление это (почти) бесплатная операция? GC (почти) никогда эти объекты не увидит и не тронет. Все ваши оптимизации привели к тому, что снизилось давление на кучу, реже стал запускаться full GC, но он все также тратит много времени на эти запуски. Не то, чтобы это вообще было бессмысленно, но такое.

Гораздо веселее разобраться почему GC тратит время на обход и компакт кучи. Если модель заточить под GC, то беспокоиться о params и итераторах уже не нужно. Я хочу сказать, что создавать сотни тысяч и миллионы объектов в секунду это не проблема, если они живут секунды. А вот напихать в кеш кучу развесистых изменяемых объектов это прямой путь к тормозам.

Sign up to leave a comment.