C# Heppard
1.56K subscribers
74 photos
2 files
122 links
25 способов эффективно использовать .NET

Поддержать канал можно тут: https://sponsr.ru/sharp_heppard
Download Telegram
Копирование массива #скорость #бенч

А вот Array.Copy. Мы можем соревноваться с ним в виде поэлементного копирования массива или, даже, сделать буффер на стеке через stackalloc и пытаться перемещать через него.

Увы, не поможет. Array.Copy будет быстрее за счёт, например, memmove. Там есть ещё пара ухищрений, но я рекомендую посмотреть их лично, перейдя к исходникам.

По вопросам реализации в своё время был интересный тред на github. Там такая масса подробностей, что мозг может задымиться.

Для нас это всё должно значить примерно следующее: по возможности нужно использовать Array.Copy (пусть даже это в виде stream.ReadAsync(buffer), а не писать велосипеды в виде побайтного копирования потока.
👍9🔥4
Доказательство существования поколений #отдых #бенч #память

Помню, на одном собесе меня попросили доказать наличие нескольких поколений памяти в .NET. Я изобразил вот такое, отталкиваясь от знаний, какие объекты попадают в LOH. Может быть кому-то понадобится.


[SimpleJob(RuntimeMoniker.Net80)]
[MeanColumn, MemoryDiagnoser]
public class LohArray
{
[Params(84900, 85000)] public int Length { get; set; }

[Benchmark]
public int LohIliNet()
{
var array = new byte[Length];
return array[0] % 2;
}
}

Сегодня я пересматриваю А.Жмур (Pragmatic memory management) и, о чудо, внезапно вспомнил, откуда я взял этот код. Как интересно работает память человека. Как в .NET)
👍13🤯4
Static в анонимных функциях #отдых #бенч

Представляется, что ключевое слово static в анонимных функциях - декларация о намерениях, не более. То есть мы как бы говорим, что по нашему мнению в данном месте точно не надо захватывать контекст и создавать объект аллокации. Бай дизайн типа.

Т.е. это не про скорость и аллокацию тема.

Код бенчмарка в чатике.

Ещё почитать про это можно в соседнем канале.
👍114
Графика для самых маленьких #графика #лекция #игра

Рекомендую хороший набор роликов по OpenGL. Лектор явно с математическим складом ума, много рассказывает о том, как это должно работать, а потом реализует в коде. Примеры с использованием OpenTK. Есть и примеры с Monogame.
👍11
Докупить память или написать эффективно? #отдых

05.03.2024 в рамках процесса *оптимизации* использования ресурсов кластера kubernetes (***) будут выключены сервисы, развернутые в следующих неймспейсах...


Когда я получаю подобные сообщения от корпоративной инфраструктуры, либо от команды RE, я всегда вспоминаю один диалог. Состоялся он, ох, уж сколько лет прошло, на одном локальном митапе. Я, как всегда, вещал про то, что было бы неплохо писать оптимальный код, в том смысле, чтобы экономить байтики и наносекунды. То да сё, слайды, смешки, лёгкое непонимание в глазах слушателей. Наконец, секция вопросов и ответов.

Я хорошо помню этого мужика, который во время доклада делал фейс-палмы, громко ёрзал стулом, сидел в телефоне. Я ждал вопросов от него и дождался.

- Скажите, а зачем всё это?
- В смысле, - не понимаю я.
- В том смысле, - сказал он авторитетно, - что это всё не нужно. Проще купить плашку в 16 ГБ памяти, чем всё это знать.

Я тогда был молод, поэтому мой ответ был слаб. Жаль. Мне кажется, что в тот момент некоторые люди разочаровались в теме. Теперь я умный, теперь я знаю что ему ответить. Ну про то, что у нас k8s, 800m процессора и 2048Mi памяти. А чтобы просить больше, надо согласования, утверждения и вообще.

Где этот дядя с 16 ГБ настоящей оперативки и, наверное, с двумя-тремя настоящими ядрами?
Отдай мне их, дядя, я всё прощу.
👍15😁11🤯1
Читая некоторые параллельные каналы а-ля .NET Разработчик или StepOne, я иногда удивляюсь. Мне кажется, коллеги иногда не внимательно слушают RadioDotNet. В очередной раз хочу его прорекламировать.

Это подкаст про:
- Новости мира .NET.
- Новинки языка C#.
- Новинки ASP.NET, EF и прочего.
- Новинки популярных библиотек.
- Обзоры статей известных авторов о мире .NET.

К каждому выпуску прикреплены статьи, код на github, всякие разные ресуры, по которым очень интересно ходить.

Для состоятельных парней, есть возможность поддержать Анатолия и Игоря на boosty. За это присылают подарки, дают доступ к болталке и ко всяким записям вне выпуска. Иногда там бывает интересно. Ребята молодцы, делают хорошее дело.

Считаю RadioDotNet одним из лучших каналов для получения оперативной информации о мире .NET.

P.S.: А вот этот канал, кажется, опережает даже RadioDotNet. Евгений молодец. Будь как Евгений.
P.P.S: И как Сергей и Степантут) тоже будь. Я вот их немного подначиваю, но они хорошие!

#лекция #статья
👍18🔥2
Свой ConcurrentDictionary #память #лекция

Кстати, ещё один камень в огород тех, кто считает, что проще купить плашку памяти, чем заняться оптимизациями.

Это скриншот из доклада Антона Нечуговских (Контур) по поводу своей собственной имплементации ConcurrentDictionary. Только и нужно - инструменты анализа, знание устройства словарей, знание модели памяти, понимание профиля нагрузки, аккуратный код.

Как результат: потребление памяти в кластере снизилось на 30-40%. Неплохо так сэкономили. Я не знаю сколько это в деньгах, но то, что они сэкономлены - нет никаких сомнений.
👍21🔥7👎1
Несколько solution в одном Rider #решение

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

Подключаем как Existing project, перезагружаем IDE (не знаю зачем, но надо) - вуаля. Иногда есть какое-то странное поведение - не получается ткнуть и переключиться на нужную ветку. Но, в целом, пользоваться можно.

Чтобы редактировать проекты локально и не связываться с пушингом в nuget каждого изменения, подключаем библиотеки вот так:


<ItemGroup>
<PackageReference
Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"
Include="***.Data"
Version="1.0.1"/>
<ProjectReference
Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"
Include="..\..\локальный_путь.Data.csproj"/>
</ItemGroup>


То есть в релизе будет библиотека из nuget'a, а в debug - локальная копия.

P.S.: Удалить проект можно в настройках: Version Control -> Directory Mappings. В окне нажимаем минусик, чтобы удалять репозитории.
🔥15👍4👎1🤯1
Где находится эффективный код #философия

737. Кажется, назрел вопрос - а кто, я, собственно, такой.

1. Привет, я - Кирилл.
2. Я программист, как и вы.
3. У меня есть бзик - производительность.
4. При этом, я не фанатик, который хочет заоптимизировать всё подряд. Я не тот, кто давит на окружающих - оптимизируй! Я имею возможность, но не делаю этого.
5. Я тот, кто хочет перевести код из состояния "не оптимальный код" в "оптимальный код" (см. рисунок - точки А в B). Максимум, дойти до "оптимизированный код" (С).
6. Но не для всех случаев. Часто, я бенчмаркаю ради того, чтобы исследовать возможности .NET.
7. Я стараюсь блюсти тему канала. Я не душню, я просто держусь темы. Мне кажется это важно, т.к. каналов про общие знания о .NET десятки.
8. Также, я понимаю бизнес. Я пять лет как lead с разными размерами команды. И да, я понимаю, что знания о производительности - дорогие знания, не нужные многим программистам, которые просто хотят заставить эту железку работать.

Я лишь хочу, чтобы мы заставляли эту железку работать оптимально.
👍451
Автор картинки выше - некий Алексей Шипилёв, хорошо известный в узких кругах Java-программистов. Картинка из доклада "Перформанс: что в имени тебе моём?", подстрочник которого находится тут.

Всем, кто так или иначе интересуется производительностью, я рекомендую просмотр и вдумчивое чтение. Это, так сказать, философия в облике фактов о Java. Одинаково применимая, кстати, к любым технологиям. В том числе к .NET.

Жаль, что в .NET нет таких людей. Некий Андрей Акиньшин мог бы, но ушёл в высокую статистику. Очень жаль. Его ранние доклады и заметки были очень классными. Посмотрите видосики. Особенно интересы замечания конферансье - "хорошй специалист, на самом самом, там, низком уровне".

#философия
🔥5👍41
Преждевременная пессимизация #философия #игра

Хотелось бы напомнить лекцию некого Дмитрия Иванова - "Сказки о преждевременной оптимизации". Лекция далёкого 2015 года. Коллега из компании, где производительность является ключевой фичей, напоминает нам о том, что мантра "Преждевременная оптимизация - корень всех зол" не всегда верна.

Например, мы исходим из предположения, что мы всегда найдём те 1-20% кода, которые тормозят всё и, конечно, поправим. Увы, нет. Иногда получается так, что 90% кода тормозят и мы вынуждены переписывать продукт почти заново.

Далеко ведь ходить не надо. Вот пример Cities Skylines 2. Вроде игрушечка, вроде могли всё написать нормально сразу. Но нет. Почему-то надо было выпуститься к определённой дате. Наверное, маркетологи и бизнес что-то знали и это, наверное, правильно. Увы, мне кажется, что они ошиблись - куча негативных отзывов тому пример.

Эта история ещё раз подтверждает тезис Дмитрия - "преждевременная пессимизация - корень зол". Т.е. если разработчики вообще не уделяют внимания элементарными подходам к производительности, то потребуется много человекочасов и масса изменений в коде, чтобы сделать всё более-менее оптимально. Это те же деньги, это то же время.

У меня в этой связи вопрос: понимает ли бизнес и донёс ли технический лидер эту простую мысль до руководства?
👍82😁1
Кто тут по поводу создания игр?

Хочу дать хороший ECS - DefaultECS. Как мне кажется, это интересная имплементация паттерна. Да, можно быстрее и лучше (см. LeoECS), но этот чувак как минимум реализовал DebuggerTypeProxy, а значит хотя бы пытался работать со своим решением.

Кстати, пользуясь случаем, хочу задать несколько вопросов по поводу ECS вообще их конкретных имплементаций. Я, знаете ли, иногда тоже балуюсь - вдруг получится реализовать лучше, чем решения коллег выше.

1. Так ли нужно создавать мультимиры? Это вопрос тестирования или чего-то ещё?
2. Там и сям у Entity есть версия. Зачем? Сделайте её ref struct и она никогда не будет хранится отдельно от контекста. Вопрос сравнения энтитей по версии стоит вообще?
3. Так ли нужно держать массив по количеству энтитей в каждом из ComponentPool? Конечно, это сильно быстрее. Но блин, если у меня 512 компонентов и 2 000 000 сущностей... Ну, например, карта 512 на 512 с юнитами.
4. Почему вы не делите данные на сущности игры, сущности настроек (ассеты?) и сущности изображений? Ну типа Actor/Asset/View?
5. Ну и, вопрос из кровавого энтерпайза, почему нет более-менее адекватной связи с подобиями MediatR? Это ж просто. И это отлично ложится на ECS.

#игра #решение
🤔4👍3🥰1
Бенч, который не работал #бенч #память #скорость

Однажды ко мне пришёл подпрыгивающий от изумления коллега, и показал примерно вот такой бенчмарк. По его замерам выходило, что Array.IndexOf по массиву с int в 300 раз быстрее применения того же метода на массиве uint. Более того, uint что-то там ещё и аллоцирует!

Ответ на эту загадку, конечно, элементарный, но показательный. Кто-то знает, в чём проблема?



Так как прошло достаточно времени, то можно написать правильный ответ прямо тут: дело в том, что при вызове Array.IndexOf(uint_array, 15), число 15 воспринимается компилятором как int, а значит перегрузка IndexOf<T>(T[] array, T value) не подходит. А значит, выбирается метод IndexOf(object[] array, object value).

Вывод: проблему сложно заметить, она не про перформанс, а про внимательность. Поэтому надо быть очень внимательным, когда мы пишем код, ведь нам очень легко получить проблему с производительностью на пустом месте. Вот как тут.

Код бенчмарка в комментариях.
👍7🤔53🔥2👎1😁1
Привет всем! Мы тут с коллегами задумали одну штуку сделать, но чтобы она была интересна и лучше понята, хотелось бы понять уровень присутствующей тут аудитории. Скажите, кем вы себя видите сейчас? Проголосуйте, это очень поможет. Спасибо!
Anonymous Poll
19%
Джун
38%
Миддл
25%
Сеньёр
5%
Тим лид
8%
Тех лид
0%
Менеджер
4%
Архитектор
👍2
Логирование и память #решение #память

Недавно разбирался со скоростью работы логирования, а также с тем, сколько логер потребляет памяти.

Эта подсистема не бесплатная и может влиять на производительность. Увы, от логов отказаться нельзя, поэтому хотелось бы всё-таки понять, как писать их быстро и экономно по памяти.

В качестве подопытного кролика выбрал Serilog, как наиболее часто используемую в разных проектах.

Победил чистый Serilog.ILogger, без прослойки в виде Microsoft.Extensions.Logging.ILogger. И дело не в скорости (она почти одинаковая), а в аллокации - у чистого Serilog она чуть меньше.

Однако, самым удивительным для меня оказалось то, что простое использование логгера было даже чуть экономичнее аналогов из советов про High-performance logging (ну все эти LoggerMessage.Define и LoggerMessageAttribute). Почему так получилось - понять с наскока не удалось.

Бенчмарк в комментариях.

P.S.: Для специалистов: писал просто в консоль через ConsoleSink, без изысков, поэтому цифры вот такие.
👍7🤔3
Массив на стеке #решение #память

С момента появления InlineArrayAttribute (мотивация) я хотел на него посмотреть в деле. Напомню, что это атрибут для структур, который "размножает" поле, в котором лежит "элемент массива". Также, атрибут добавляет индексатор для доступа к значениям, чтобы структура стала похожей на массив. Значения через индексатор попадают в сгенерированные поля, откуда могут быть получены позже.

И это всё на стеке, т.е. тот самый zero-allocation.

[System.Runtime.CompilerServices.InlineArray(10)]
public struct Buffer10
{
private int _element0;
}


Единственная проблема: по поведению это массив, т.е. не List, который может расширяться. Это накладывает определённые ограничения на применение данной фичи. Конечно, выход существует и его придумали давно (см. тут): при достижении предела локальных полей мы создаём честный массив, куда складываем "избыток" значений.

С появлением InlineArray эти два подхода можно объединить. Получается неплохо: и быстрее и экономнее по памяти. Кода много, поэтому он тут.

Представить InlineArray как Span тоже просто - Span<int> span = myBuffer. Это позволит применить любые подходы работы со Span для всех структур, отмеченных InlineArrayAttribute.
🔥19👍32
Недавно опубликовали первое видео с последнего DotNext. Мне приятно, что первым опубликованным был некто Евгений, и про производительность.

Почему доклад может быть интересен?

1. Евгений отмечает, что BCL весьма оптимизирована для общих случаев и может считаться одной из самых хороших частей приложений на .NET в смысле производительности.

2. Поднимает важную тему сторонних библиотек, которые не могут или не хотят думать о производительности. Я это называю болезнью Middle-разработчика. Ты как бы уже можешь написать хорошее решение, но ещё не знаешь, как это сделать оптимально.

3. Евгений подтверждает мой личный опыт. Когда я в отчаянии, и в сотый раз пишу свою игру, я почти не пользуюсь сторонними решениями - ну кроме работы с OpenGL/DirectX. Как раз потому, что сторонние решения были написаны до эры Span'ов и прочего инструментария серьёзных парней для улучшения производительности.

4. Затрагивает особенности работы с ArrayPool в многопоточной среде, а также для маленьких массивов.

5. Упоминает интересную тему с LOH. Считается, что LOH это плохо. На самом деле плохо - это фрагментация кучи. Если у вас есть большой массив, его надо обязательно поместить в LOH и это будет более эффективно, чем заставлять GC спотыкаться о маленькие массивы.

6. Рассказывает про логирование. Детальный разбор будет позднее, если руки дойдут. Слушать интересно. Моя позиция неизменна - инфраструктура не должна аффектить производительность основного кода, либо делать это минимально. Будь то логирование или этот ваш MediatR.

7. Уделяет внимание InlineArrayAttribute.

8. Правильно указывает на то, что record мог бы стать отличным местом для кодогенерации. Когда фича только появилась, я так и думал, что это оттуда. Оказалось, увы, нет.

9. Упоминает меня с рассказом про S3. Надеюсь, видео скоро опубликуют.

#философия
👍155
Сколько сейчас платят #деньги

Коллеги, хочу сделать новую рубрику: актуальные данные по зарплатам.

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

Цифры без учёта бонусов и прочего, чистые деньги после налогов по зарплатам в месяц. И только по dotnet'у. Деньги в тысячах.

Архитектор: 400-500.
Тимлид:
350-400.
Техлид:
400-480.
Сеньёр:
380-420.
Миддл:
250-300.
Джун:
среди моих знакомых нет, извините.

Видно, что зарплаты хорошие, достойные. В разных компаниях к этому предлагают ещё бонусы, тринадцатые зарплаты и разовые премии.

Важные замечания:
1. Данные основаны на опросах моих знакомых и знакомых знакомых. Выборка не репрезентативная, то есть это моё личное мнение, а также мнение тех, кто мне дал цифры. Для среднего по больнице и для вычислений не подходит.
2. Ценники даются как есть, то есть без выводов. Каждый их делает для себя.
3. Для меня нет разницы между компанией Рога и Копыта и большой компанией. Как получилось, так и получилось.
4. Данные по разным странам, эквивалент в рублях.
5. Игропром не учитывается. Просто тупо нет знакомых.
6. Ещё раз: премии не учитываются. Да, понятно, что премии могут быть x100 от ЗП. Но у меня просто нет таких данных.
7. Если у вас есть какие то другие данные или замечания - пишите. Давайте делиться информацией о рынке труда.
👍34🔥1🤔1
CollectionsMarshal #память

Ваши коллеги любят List<T>, а вы желаете окунуться в мир Span<T>? Выход есть!


List<int> list = [1, 2, 3, 4, 5];
var span = CollectionsMarshal.AsSpan(list);


Ваши коллеги любят Dictionary<TKey, TValue>, а вы, в тайне от них, мечтаете пощупать механику работы с ref? Выход есть снова!


var dic = new Dictionary<int, int>
{
{ 1, 1 },
{ 2, 2 }
};

ref var value = ref CollectionsMarshal.GetValueRefOrNullRef(dic, 2);
if (!Unsafe.IsNullRef(ref value)) value = 2222;
Console.WriteLine(dic[2]);


Вам надоело передавать структуры через Nullable<T> и вы мечтаете быть модным и шелковистым? Опять выход рядом! Обратите внимание на конструкцию Unsafe.IsNullRef(ref value) из предыдущего кода. Если в словарик передать не существующий ключ, то он сделает return ref Unsafe.NullRef<T>(). Этот результат очень удобно проверять на null.

Короче говоря, если кто не знал, есть такой интересный класс CollectionsMarshal. Иногда помогает делать странное. Например, достучаться до внутренних массивов BCL-коллекций и работать с ними, когда вам нужны ссылки на элементы.
🔥25😁7👀2👍1
Антиреклама .NET #решение #память #скорость

Я специально не писал про Garnet, хотя и признаю - это отличная тема про производительность.

Однако, с моей точки зрения, это весьма сомнительная штуковина в плане имплементации (см. вот эту дискуссию). Да, скорость это круто. Да, оно работает. Да, я бы на него перешёл хотя бы из-за лицензии. Но я не понимаю коллег, которые его создали. Ну, чисто как разработчик. Ведь что мы имеем?

Множество unsafe, свой собственный менеджер памяти для того, чтобы миновать GC. Поверх этого имеем кучу специальных подходов, которые могли быть заменены на подходы современного C#. Кстати, без изоленты и палок.

Зачем это было? Мол, прикинь, братва, как много хаков можно написать в коде? Супер, спасибо. А мы не знали.

Я, после этого, не понимаю что отвечать своим знакомым джавистам. Они спрашивают, мол, шарписты реально пишут вот так? А я им пытаюсь объяснить про студентов, про много денег и времени, которые у них были. И про то, что я занимаюсь не этим. Мол, если мне надо прям вот так, я иду на Rust, а не мучаю кошек.

Хотелось бы видеть от MS настоящие проекты на обычном C#. Особенно, если они его рекламируют как то, что должно привлечь новых разработчиков. Увы, кажется, получилась антиреклама.
👍27👎2
Мониторинг приложения #решение #память

В Rider появился инструмент поверхностного мониторинга работающего приложения. Этот функционал IDE будет знаком пользователям Visual Studio.

1. Мониторинг запускается при старте приложения. Начинают бежать графики размеров куч и загрузки CPU. Полезно для того, чтобы быстро кинуть взгляд на состояние приложения.

2. Вкладка Counters полезна счётчиками запросов к вашему ASP.NET приложению. Коллегам от перформансного цеха там будет интересна фрагментация кучи, GC-time в миллисекундах и чёткие циферки по размерам куч.

3. Вкладка Environment содержит ключи и значения, с которыми запущено приложение.

4. Особенно приятно, что всё это великолепие можно отключить.
👍21😁16