Комментарии 20
Было бы неплохо, если в readme была бы строчка о том, как этот анализатор подключить к своему проекту...
Когда вы видите время метода 0.012ns у вас ничего в голове не щелкает? Бенчмаркдотнет много пытается вернуть адекватные числа, но иногда нужно включать мозг все же. Не вижу полных данных с указанным процессором и модальностью распределения, но, наверное, вы сможете поделить секунду на гигагерцы.
Как-то встречал реализацию проверки есть ли что-то в массиве или в list просто проверкой нулевого индекса. Ну и try ... catch конечно. Смешновато конечно, типично индусский код. Но тоже имеет право на жизнь.
У массива фиксированный размер, который указывается при создании. Иными словами, если массив не нулевой длины, в нем всегда "что-то есть", по каждому индексу. Да, существует Resize, который по сути пересоздает массив с новым Length. Но в любом случае, Length у массива всегда известен. List это надстройка над массивом, у которой Count также всегда известен. Он НЕ равен Length массива под капотом, но все равно сохраняется в интовом поле, всегда доступен и ничего быстрее Count == 0 не придумать. Если зачем-то хочется все же получить внутренний массив из листа есть CollectionMarshall.AsSpan(List list) который возвращает спан, что еще лучше чем массив. CollectionMarshall даже позволяет установить Count листу, что чревато катастрофой, если его установить неправильно.
Что-то оптимизировать имеет смысл только при работе с LINQ. Там часто производительность жертвуется в пользу универсальности и совместимости, поэтому выигрыш там может быть существенным на соответствующих задачах. Правда смысла все меньше, потому что команда дотнет и так оптимизирует LINQ с каждой версией, и делает это очень неплохо. Но если вдруг супероптимизация необходима здесь и сейчас, есть https://github.com/Cysharp/ZLinq вот такая либа, очень и очень на сегодня рабочая. Хотя с каждой мажорной версией дотнета теряет актуальность.
Да я то это знаю.
Говорю-же встречал такое:List<string> list = new();
... тут что делаем...try
_ = list[0];
catch
//А лист то пустой
Понятно что бред.
Меня больше интересует проверка
if
(count >= 0)
Вот интересно, а может ли в реальном коде быть count < 0 и какой смысл в это закладывается? Эта даёт какую-то микрооптимизацию на уровне IL/asm, перестраховка на то, что кто-то в своей реализации интерфейса так пометил специальный случай или просто в жизнь старый анекдот воплощают?
Математики шутят...
В аудитории лектор читает лекцию по математике трем студентам. Внезапно встает пять человек и уходят. Лектор:
- Вот сейчас придут еще двое, и вообще никого не останется.
Ну сову на глобус натянуть можно. Хотя чисто в теории... Хотя даже в теории все равно... count это int, а не uint. Хотя... Если count = -1;
try
count = list.count();
catch
И тут дальше какая-то логика когда "-1" это индикация что list вообще не инициализировался даже с нулевой длиной. Это чисто в теории, естественно нужно делать по другому.
Count >= 0 это очень странная проверка, если равно нулю - лист пустой, если больше - не пустой ) Проверяют либо одно, либо другое.
Отрицательный счетчик в реальном коде быть не может. Я писал выше, что при желании можно установить Count принудительно, и (скорее всего, не проверял) поставить туда отрицательное число тоже можно. Но смысла в этом никакого нет, так как лист перестанет корректно работать.
Если вопрос про код из статьи, где count берётся из listProv.GetCount(onlyIfCheap: true)
, то эта проверка имеет смысл: если получить count не дёшево, вернётся -1.
Ловить эксепшен намного, намного хуже по производительности чем буквально что угодно. Использовать эксепшены для управления вообще не рекомендуется в наше время.
Если посмотреть реализацию листа, там в индексаторе проверка выхода за рэнж осуществляется путем сравнения с тем же самым Count, если индекс >= Count выбрасывается эксепшен.
Стоит отметить, что когда идет работа с обобщениями IEnumerable<T>, то желательно проходится по стриму данных один раз.
В случае же коллекций из серии *Concurrent, они могут меняться пареллельно обработке. И для комбинаций сложнее ToArray\Count\Any стоит использовать внешний локер.
Использование потокобезопасных коллекций - антипаттерн.
Объяснил кратко в конце статьи https://habr.com/ru/articles/803273/
Сами себе проблем нашли и сами с ними борятся...
В C++ , empty() работает за O(1), всегда, на всех коллекциях
В Rust is_empty(), на атомарных операциях, работает всегда за O(1) на всех коллекциях
Нельзя просто так взять и выбрать Any() или Count для проверки коллекции