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

Поддержать канал можно тут: https://sponsr.ru/sharp_heppard
Download Telegram
Графика HTMLCanvas #графика #скорость

Рекомендую хорошую статью про Rust, SIMD, WebAssembly и GPU. Разницу в подходах можно пощупать онлайн. В принципе, вывод очевиден - использовать GPU при работе с графикой сильно выгоднее. Однако путь автора и попытки добиться высокой производительности без GPU потрясают.

Эта статья (вернее, её первая часть) стала для меня важным мостиком в мир Rust и WebAssembly. До этого я не очень представлял, как вообще всё это заставить работать вместе.
Скрипты в .NET #решение

Однажды я искал библиотеку, чтобы писать скриптики на JS и работать с ними из .NET. Ну знаете, достать из БД логику, которую написал заказчик без участия программиста, на лету изменить поведение приложения, розовые пони... эх, мечты-мечты.

Но библиотеку я запомнил. Поэтому, могу рекомендовать познакомиться с ней тем, кто ещё хочкт прикрутить скриптики на JS. Бенчмарки неплохие, парни из RavenDB и Orchard используют.
👍1
Как работает память #память

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

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

Узнал про это из подкаста Radio Dotnet. В этом выпуске около часа рассказывают про оптимизации в .NET 7. Очень занимательно.
👍1
Тинькофф написал статью про последние митапы про .NET. Я там тоже есть, но в данном случае хочу порекомендовать вот это (про оптимизации компилятора, осторожно - много IL). И вот это (про lock-free, но на самом деле про обычные concurrent-коллекции).

Руслана (про боль и микросервисы) с Николаем (проектная документация) тоже порекомендую. Их доклады не совсем по теме канала, но они клёвые.

#статья
👍4
PostgreSQL vs MongoDB #хранилище #лекция #решение

Рекомендую достаточно старое видео на тему PostgreSQL vs MongoDB. Недавно пересматривал из-за необходимости выбора. Остановился на PG. Сразу после этого видео рекомендую второе. Оно в тему.

Во втором видео есть интересное объяснение того, что такое highload (high-volume). По версии "человека с лицом индейца" (его зовут Олег Бартунов, если что), это "ситуация в системе, грозящая отказом в обслуживании из-за недостатка ресурсов". Там же про ошибки проектирования. Напомню, что "проектированием" иногда называют само программирование. То есть ваша логика должна быть заточена на highload.
🔥2👍1
Dapper #решение #хранилище

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

Так вот, Dapper. Это просто data-mapper. Собственно, именно то, что вам нужно иметь для получения ответа от DB. Он тупо создаёт объектное представление из данных, которые возвращает в БД. Запрос вы пишете сами. Прям в коде, да. В 60% случаев вам нужно именно это.

Да, у него нет контекста (см. Entity Framework), да, SQL вам нужно писать самим (на самом деле нет и нет). Но возможность писать оконную функцию без бубна, возможность писать взаимодействие с JSONB, возможность бежать по view, возможность использовать поиск, dirty read... Ну это многого стоит.

Да, нужно изучить SQL (уровень программистов в команде должен быть выше), но это именно тот путь, через который вам доступна максимальная производительность.
👍5
Честный TechEmpower #бенч #статья

Мужчина очень хорошо рассказал на тему качества бенчмарка Web Framework Benchmarks от TechEmpower.

В принципе, было очевидно, что циферки натягивают на бенчмарк - такой маркетинговый повод! С другой стороны, разработчики продемонстрировали возможности платформы .NET по микрооптимизации, что меня очень радует.

Также, меня радует, что тест уровня Core MVC + EF + PG (самый плохой тест) с моей точки зрения показывает хороший результат - 184k запросов в секунду. Да, это не топ. Да, эту цифру нужно уменьшить до 18-20k за счёт дополнительных слоёв проверок, абстракций типа Mediator и всего прочего.

Но это 20k запросов в секунду. Которые, при желании, можно превратить в 184k или даже в результат синтетического теста (400k+ запросов). Было бы желание.
👍3
Хороший GUID #хранилище #решение #статья

Недавно вдумчиво читал статью про медленную работу Guid.NewGuid() на некоторых версиях Linux. Интересно, что про подобное я уже слышал на Radio Dotnet, но в контексте создания GUID, основанных на времени (это помогает, например, забирать сущности из БД по одной страничке для UI).

Короче, суть в том, что на некоторых версиях Linux генерация GUID идёт с помощью чуть более медленного алгоритма, чем на Windows. Если у вас именно такая ситуация, то рассмотрите вопрос перехода на другую версию Linux, либо воспользуйтесь предложениями перехода на другие алгоритмы из этой же статьи.

И обязательно посмотрите на рассуждения Эндрю Лока о монотонно возрастающих GUID . Их использование потенциально способно решить проблему фрагментации индекса в MSSQL (увеличение времени вставки, поиска по ID из-за разреженности индекса и рост размера БД). Говорят, что PostgreSQL таким не страдает, но не мешает проверить. Готовое решение для создания монотонно возрастающих GUID называется NewId.

Подробно про это всё написали вот тут.
👍7
Решил на выходных развлечься: протестировал работу клиентов для S3. Выпил чаю, развернул Minio в Docker'e, и обработал его вполне типичными запросами из различных клиентов.

Что конкретно я сделал:
1. Проверил наличие bucket'a.
2. Поместил в хранилище файлик на 125 МБ.
3. Посмотрел, что файлик есть.
4. Скачал его.
5. Удалил.

В принципе, все клиенты справляются быстро, до 2 секунд. Но есть нюанс по памяти: с моей точки зрения, клиенты от Amazon и Minio кушают слишком много. А ведь я ничего особенного не сделал.

Из ощущений по использованию. AWS клиент многословный, трудный. Клиент от Minio лучше, но нас лишили Multipart-загрузки (включается автоматически, при файле больше 5 МБ). Клиент для Yandex - суровое поделие JS-разработчиков. Вроде контракт приятный, но стоит копнуть глубже - мрак, сразу мимо.

Короче говоря, посмотрел я код и... решил написать сам. Результаты на .NET 7 следующие: скорость почти как у Minio, а памяти ем почти 200 раз меньше. Код посмотреть тут.

#хранилище #бенч
👍13🔥2
Без какой-либо цели тестировал аллокацию. Дано: приложение с выставленным gRPC контрактом + Dapper + PostgreSQL. По gRPC приходит запрос (проверка наличия элемента), сходили в БД, в ответочку вернули false. И так миллион раз.

Всё. Какой же результат мы видим по аллокациям?

Правильно, я забыл про Serilog (пишу в консоль). Именно он бешено аллоцирует строчечки. Его аллокации на первом месте. Приятная новость в том, что все они в Gen0. Неприятная новость: раз в 10 секунд GC вынужден вычищать по 300Мб памяти.

#скорость #память #анализ
Как же я забрасывал сервис миллионом запросов (см. предыдущее сообщение)? Ну, не миллионом, положим, но их было много. Просто запустил benchmark. Кстати, в качестве обёртки для gRPC использую protobuf-net.

Аллокация в норме, время выполнения чаще всего быстрее (просто на другой стороне был профайлер по памяти - это немного тормозило ответы).

Вообще, скорость меня впечатлила - мы сериализовали сообщение (пусть и простое), сходили по сети, десериализовали на той стороне, сходили в БД, где тоже сериализовали и десериализовали. Потом сериализовали снова, вернули и десериализовали. Ух... И всё это за 1-2 мс. Круто.

#скорость #бенч
👍3
Комментарии есть?
Внутренности HTTPClient #лекция

Недавно, кстати, Евгения пересматривал. Как раз в связи с клиентиком для S3. А тут, оказывается, Евгений ведёт канал в телеге - можете сходить, мне нравится.

Видео рекомендую для погружения (или освежения воспоминаний) в работу с HTTP в .NET. Много нюансов, которые не очевидны некоторому количеству разработчиков.
👍6
Снижение размера сборки #память

Появилось мнение о будущем размере Hello World в .NET 8. Мнение поддерживает человек по имени Егор Богатов. Лицо у него светлое, кажется, что ему можно верить.
🔥2
Хочу порекомендовать подкаст Podlodka. Не так давно некий Игорь Лабутин рассказал про .NET аж в двух частях: первая и вторая. Мне кажется, получилось легко и интересно.

Сам подкаст скорее около IT-шный, его приятно слушать, чтобы быть в теме всего того, что существует за пределами .NET. Чего-то особенного про производительность я там не помню, но так или иначе иногда и эта тема затрагивается.

#лекция
👍5
CLRium #лекция #память #скорость

Сегодня переслушивал CLRium #4 про Span и Memory, чтобы попытаться найти решение проблемы с разной аллокацией на разных операционных системах. В принципе, как и 4 года назад, Станислав вещает интересно, хоть и своеобразно.

Если кто не знает, что такое CLRium, то очень рекомендую. Я, как "Войну и Мир", слушал эти лекции раз по десять. И каждый раз извлекал для себя что-то интересное. Глубокое погружение во внутреннее устройство .NET гарантировано.
🔥10👍5
Пульнул на Хабр три старые заметки: про Dictionary<int, T>, про очевидный for или foreach и про inline и throw. В своё время думал, что добавлю туда больше интересного, но за почти год - ничего. Решил закинуть в первозданном виде.

Из интересных наблюдений: заметки писал почти год назад, за это время люди удалили статьи с Хабра, закрыли каналы на Youtube и переписали код .NET. Как быстро летит время.

#статья #память #скорость
👍5
Скорость вызова методов #скорость

Давайте вспомним, что такое call и callvirt в IL. Call - это прямой вызов метода, без определения его адреса в рантайме. Он несколько быстрее, чем Callvirt, который требует рантайма, чтобы определить адрес вызываемого метода. И не важно, объявлен ли метод как virtual. Callvirt и ключевое слово virtual это разные понятия: одно из языка, а другое из реализации работы платформы.

Как определить, что будет Call? Тут очень просто. Call будет только в том случае, если метод статический или если работаем со структурой (кроме случаев boxing'a, например, обращения через интерфейс). Ещё есть изменение в .NET 7, которое позволяет не делать callvirt в случаях sealed классов - тоже рабочая схема.

Про статические абстрактные методы в интерфейсах не спрашивайте, не знаю как работает.

Во всех остальных случаях будет будет Callvirt:

1. Вызывается виртуальный или абстрактный метод.
2. Вызывается метод интерфеса (со своими нюансами, например, если имплементация всего одна, то будет быстрее).
3. Вызывается переопределённый метод.

Собственно, именно поэтому я часто использую структуры - чтобы повысить производительность. Иногда удачно, иногда - нет.

Прочитать достаточно старые статьи можно вот тут и тут. Прочитать короткое, но свежее, обсуждение можно вот тут. Ну, а моя заметка появилась благодаря вот этому вопросу.
🔥12