All streams
Search
Write a publication
Pull to refresh
-2
0
Send message

Это сейчас всерьёз, про коллекции?

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

Предложенные варианты вообще ни в какие ворота, конечно, НО - они работают, если уж так прям нужно.

Expressions медленные
Expression.Lambda - тяжёлая вещь.

Не настолько.
Плюс ламбда в EF не компилируется.

Да и мусор от них вряд ли переживёт ген0 при таком использовании.

Чисто формально - .НЕТ открытый проект, куда бы МС не ушёл, на возможность пользоваться .НЕТом это не повлияет.

Дальше, .НЕТ - от рантайма-джита, через базовую библиотеку и до дизайна языка и компилятора - громадный и интереснейший кусок знаний (и опыта), развивающийся у нас на глазах.

Так что хотя бы с этой точки зрения должно быть познавательно.

Ну и возвращаясь к уходу МС - было бы, конечно, здорово и интересно всё это импортозаместить - да хотя-бы даже реализовать рантайм-джит для Эльбруса или только MAUI для авроры (или как там её?), но я/ты/он/она такое организовать не потянем, а заинтересованности у тех, кто мог бы, к сожалению, не заметно.
А могло бы стать шагом к какой-нибудь православной хармони-ос.

существует большая русскоязычная община в других странах

И вас, судя по всему, могут сильно удивить настроения большой части этой общины

обманывать, рассказывать как коварный запад недобро смотрит на нашу беларусь и как плохо живут бомжи в америке.

И что из этого неправда?

Я говорил именно про долгие CPU-bound таски, которые тредпул плохо переваривает.

Так а что имеется ввиду под "плохо переваривает долгие CPU-bound задачи"?

Вообще, долгая CPU-bound - это идеальная задача с точки зрения производительности, часто недостижимая.

О. не туда ответил, оказывается. См. ниже.

https://habr.com/ru/companies/skbkontur/articles/832742/comments/#comment_27113534

Просто утверждение было слишком общее и (как минимум поэтому) слишком некорректное.

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

Так что ещё раз: с точки зрения чистого перфоманса, несколько долгих задач будут гораздо выгоднее множества коротких.

А дальше, конечно, начинаются нюансы - что важнее, пропускная способность, общее время выполнения или "отзывчивость", сколько (много ли) задач нужно создать "авансом" или есть возможность организовать ограниченный буфер создаваемых задач (backpressure) и т.д., и т.п.

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

чем задача дольше, тем хуже это может сказаться на перформансе

А можно немного раскрыть мысль?

...а где девиртуализация - там и возможный автоматический инлайнинг на уровне JITа.

А где структуры - там и локальность данных.

Нахлынули воспоминания ;)

Ускорение здесь линейно от количества вызовов горячего пути для получения результата. И если вызовов миллионы или миллиарды - запросто.

С#.

Если вкратце, то здесь два аспекта: девиртуальзация и обход боксинг.

С девиртуализацией всё просто: void Method(IInterface strategy) и void Method<T>(T strategy) where T : IInterface в рантайме будут скомпилированы в машкод по-разному. Вариант с дженериком может быть полностью девиртуализирован JITом (зависит от конкретной имплементации T, конечно, но исходим из того, что T написан правильно с точки зрения перфоманса). JIT в .нете становится умнее и старается девиртуализировать и интерфейсы/абстрактные классы/виртуальниые методы и даже делегаты на горячем пути, но это всё эвристики и без гарантий.

Боксинг: выше я писал "структуры всюду, где только можно (и имеет смысл)". "Всюду" означает как для данных, так и для логики, отличный пример - енумераторы. Стандартный пример - енумератор класса List<>, реализован как struct. Для того, чтобы он не был boxed, вызывающий код/JIT должны знать, что это List<T>.Enumerator, а не IEnumerator<T>, возвращаемый из IEnumerable<T>.GetEnumerator().

Таким же образом реализуем "стратегии" - struct имплементации интерфейсов IStrategy. new Struct()/default(Struct) создаётся на стеке, не нагружает GC. Главное, избежать боксинга, а значит передавать не как IStrategy, а как T where T : IStrategy.

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

Так получаются "десятки генерик-аргументов" о которых я писал. "Десятки", наверное, перебор, но по 10+ у нас бывало.

...про кэш-лайны и локальность данных ещё забыл ;)

Да вот именно, что как раз подобные низкоуровневые хаки и были, я как увидел шапку статьи - так сразу зашел почитать, хотя от Го далёк.

Конретно у нас "хаки" были вроде девиртуализации любыми способами (отказ от интерфейсов, виртуальных методов, делегатов, десятки генерик-аргументов - правда генерики в том числе для обхода возможного боксинга), структуры всюду, где только можно (и имеет смысл) в обмен на удобство наследования и переиспользование кода, поиск оптимальных размеров структур и хаки с паддингами/выравниванием, небезопасные балк-операции прямо над памятью вместо обращению к полям/пропертям, ручной инлайнинг повсюду (привет дублированию кода), небезопасное приведение типов (практически всюду), обход проверок границ, арифметика с указателями, ин-проц и ин-мемори всего, что только возможно, практически весь горячий путь не следовал вообще никаким "хорошим паттернам и практикам", а точнее - весь был написан вопреки.
Это только первое, что пришло на ум. Хватит? ;)

Алгоритмы и архитектура (уровня классов/модулей/внутреннего дата-флоу, в первую очередь) тоже, конечно.

Доля "хаков" в приросте производительности была действительно львиная.

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

Уменьшение времени выполнения с суток до часов, а то и минут - лично наблюдал.

Или ускорение превью рана с минут до секунд(ы).

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

А в чём суть возражений?

...что-то заигрался я в бенчмарки, но тут интересное:

NET8
NET8

При добавлении заранее отсортированных элементов у SortedList скорость ожидаемо растёт, а у SortedDictionary - неожиданно падает. Хотя если подумать - слишком часто приходится перебалансировать дерево.

В общем, нюансов у этих Sorted* масса, как я уже писал: если нужна производительность - скорее всего придётся писать своё специализированное.

А, ну и да - SortedDictionary выделяет память в куче при каждом добавлении - это означает, что его не имеет особого смысла пулить/переиспользовать, а вот SortedList - стоит.

Плюс у SortedList можно установить Capacity, и он не будет выделять новые массивы при добалении элементов в рамках установленной capacity.

Ну и ещё одна мелочь - внутри у SortedList не список, а два массива - ключи и значения.

Information

Rating
Does not participate
Registered
Activity