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

Поддержать канал можно тут: https://sponsr.ru/sharp_heppard
Download Telegram
Тинькофф написал статью про последние митапы про .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
RavenDB #решение

Если кто-то не знал, на C# написана настоящая NoSQL база данных - RavenDB.

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

Множество мелких фишек, не очень очевидных оптимизаций и даже реализаций целых look-free словарей. Кстати первоначальная реализация concurrent lock-free принадлежит некому VSadov - туда тоже рекомендую сходить. Но я так понимаю, что в RavenDB это ещё и обработали напильником под свои нужды.

Короче говоря, если вас спросят, а применяются ли микрооптимизации в реальных работающих приложениях? Можете смело отвечать "да" и называть RavenDB. Они это делают.

И не только они, между прочим.
👍6🔥5
Я люблю эксперименты, в том числе с попытками использовать JS в .NET. Для целей скриптов, разумеется. Всякие там парсеры, лексеры - очень интересно. Недавно набрёл на коллегу, который активно пилит подобное решение.

Мне такие эксперименты очень близки, поскольку лет 5 назад я сам пытался создать движок для исполнения JS на .NET. Естественно, с сильным закосом под крайне быстрое чтение данных с диска, оптимальное формирование AST и прочее. Дело было муторное, застопорилось на попытке качественно покрыть тестами. Их должно быть много (действительно много), что мне в то время было сделать крайне сложно.

А тут, живой код, который растёт, развивается и даже работает. Автор, кстати, ведёт канал в телеге.

#решение
Некий Бен Уотсон недавно напомнил о том, как они в Bing шли к .NET 5, почему для них важна производительность и что они скоро планируют начать тестирование .NET 8. Кстати, Bing - ещё один пример живого проекта, где в production применяются подходы написания высокопроизводительного кода на C#.

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

#книга
👍7