Хороший GUID #хранилище #решение #статья
Недавно вдумчиво читал статью про медленную работу
Короче, суть в том, что на некоторых версиях Linux генерация GUID идёт с помощью чуть более медленного алгоритма, чем на Windows. Если у вас именно такая ситуация, то рассмотрите вопрос перехода на другую версию Linux, либо воспользуйтесь предложениями перехода на другие алгоритмы из этой же статьи.
И обязательно посмотрите на рассуждения Эндрю Лока о монотонно возрастающих GUID . Их использование потенциально способно решить проблему фрагментации индекса в MSSQL (увеличение времени вставки, поиска по ID из-за разреженности индекса и рост размера БД). Говорят, что PostgreSQL таким не страдает, но не мешает проверить. Готовое решение для создания монотонно возрастающих GUID называется NewId.
Подробно про это всё написали вот тут.
Недавно вдумчиво читал статью про медленную работу
Guid.NewGuid()
на некоторых версиях Linux. Интересно, что про подобное я уже слышал на Radio Dotnet, но в контексте создания GUID, основанных на времени (это помогает, например, забирать сущности из БД по одной страничке для UI).Короче, суть в том, что на некоторых версиях Linux генерация GUID идёт с помощью чуть более медленного алгоритма, чем на Windows. Если у вас именно такая ситуация, то рассмотрите вопрос перехода на другую версию Linux, либо воспользуйтесь предложениями перехода на другие алгоритмы из этой же статьи.
И обязательно посмотрите на рассуждения Эндрю Лока о монотонно возрастающих GUID . Их использование потенциально способно решить проблему фрагментации индекса в MSSQL (увеличение времени вставки, поиска по ID из-за разреженности индекса и рост размера БД). Говорят, что PostgreSQL таким не страдает, но не мешает проверить. Готовое решение для создания монотонно возрастающих GUID называется NewId.
Подробно про это всё написали вот тут.
Хабр
Сказка про Guid.NewGuid()
C#. Guid.NewGuid() . Linux. Windows. Randomness or Uniqueness. RNG and PRNG. Performance. Benchmarking. Цель нашей сегодняшней сказки — развлечься как следует. Детективная история в поисках...
👍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 раз меньше. Код посмотреть тут.
#хранилище #бенч
Что конкретно я сделал:
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Мб памяти.
#скорость #память #анализ
Всё. Какой же результат мы видим по аллокациям?
Правильно, я забыл про Serilog (пишу в консоль). Именно он бешено аллоцирует строчечки. Его аллокации на первом месте. Приятная новость в том, что все они в Gen0. Неприятная новость: раз в 10 секунд GC вынужден вычищать по 300Мб памяти.
#скорость #память #анализ
Как же я забрасывал сервис миллионом запросов (см. предыдущее сообщение)? Ну, не миллионом, положим, но их было много. Просто запустил benchmark. Кстати, в качестве обёртки для gRPC использую protobuf-net.
Аллокация в норме, время выполнения чаще всего быстрее (просто на другой стороне был профайлер по памяти - это немного тормозило ответы).
Вообще, скорость меня впечатлила - мы сериализовали сообщение (пусть и простое), сходили по сети, десериализовали на той стороне, сходили в БД, где тоже сериализовали и десериализовали. Потом сериализовали снова, вернули и десериализовали. Ух... И всё это за 1-2 мс. Круто.
#скорость #бенч
Аллокация в норме, время выполнения чаще всего быстрее (просто на другой стороне был профайлер по памяти - это немного тормозило ответы).
Вообще, скорость меня впечатлила - мы сериализовали сообщение (пусть и простое), сходили по сети, десериализовали на той стороне, сходили в БД, где тоже сериализовали и десериализовали. Потом сериализовали снова, вернули и десериализовали. Ух... И всё это за 1-2 мс. Круто.
#скорость #бенч
👍3
Внутренности HTTPClient #лекция
Недавно, кстати, Евгения пересматривал. Как раз в связи с клиентиком для S3. А тут, оказывается, Евгений ведёт канал в телеге - можете сходить, мне нравится.
Видео рекомендую для погружения (или освежения воспоминаний) в работу с HTTP в .NET. Много нюансов, которые не очевидны некоторому количеству разработчиков.
Недавно, кстати, Евгения пересматривал. Как раз в связи с клиентиком для S3. А тут, оказывается, Евгений ведёт канал в телеге - можете сходить, мне нравится.
Видео рекомендую для погружения (или освежения воспоминаний) в работу с HTTP в .NET. Много нюансов, которые не очевидны некоторому количеству разработчиков.
YouTube
Евгений Пешков — Клиентский HTTP в .NET: От WebRequest до SocketsHttpHandler
Подробнее о конференции DotNext: https://jrg.su/3WmFRE
— —
На первый взгляд кажется, что отправить HTTP запрос — это очень просто. Тем не менее, даже HTTP/1.1 достаточно нетривиален: RFC на него содержит более 150 страниц, кроме того, браузеры уже поддерживают…
— —
На первый взгляд кажется, что отправить HTTP запрос — это очень просто. Тем не менее, даже HTTP/1.1 достаточно нетривиален: RFC на него содержит более 150 страниц, кроме того, браузеры уже поддерживают…
👍6
Снижение размера сборки #память
Появилось мнение о будущем размере Hello World в .NET 8. Мнение поддерживает человек по имени Егор Богатов. Лицо у него светлое, кажется, что ему можно верить.
Появилось мнение о будущем размере Hello World в .NET 8. Мнение поддерживает человек по имени Егор Богатов. Лицо у него светлое, кажется, что ему можно верить.
🔥2
Хочу порекомендовать подкаст Podlodka. Не так давно некий Игорь Лабутин рассказал про .NET аж в двух частях: первая и вторая. Мне кажется, получилось легко и интересно.
Сам подкаст скорее около IT-шный, его приятно слушать, чтобы быть в теме всего того, что существует за пределами .NET. Чего-то особенного про производительность я там не помню, но так или иначе иногда и эта тема затрагивается.
#лекция
Сам подкаст скорее около IT-шный, его приятно слушать, чтобы быть в теме всего того, что существует за пределами .NET. Чего-то особенного про производительность я там не помню, но так или иначе иногда и эта тема затрагивается.
#лекция
podlodka.io
Podlodka Podcast
Еженедельный подкаст про IT и все, что с ним связано.
👍5
CLRium #лекция #память #скорость
Сегодня переслушивал CLRium #4 про Span и Memory, чтобы попытаться найти решение проблемы с разной аллокацией на разных операционных системах. В принципе, как и 4 года назад, Станислав вещает интересно, хоть и своеобразно.
Если кто не знает, что такое CLRium, то очень рекомендую. Я, как "Войну и Мир", слушал эти лекции раз по десять. И каждый раз извлекал для себя что-то интересное. Глубокое погружение во внутреннее устройство .NET гарантировано.
Сегодня переслушивал CLRium #4 про Span и Memory, чтобы попытаться найти решение проблемы с разной аллокацией на разных операционных системах. В принципе, как и 4 года назад, Станислав вещает интересно, хоть и своеобразно.
Если кто не знает, что такое CLRium, то очень рекомендую. Я, как "Войну и Мир", слушал эти лекции раз по десять. И каждый раз извлекал для себя что-то интересное. Глубокое погружение во внутреннее устройство .NET гарантировано.
YouTube
CLRium #4. Span'T, Memory`T (Сидристый Станислав)
Новые типы данных, которые имеют не побоюсь этого слова революционный характер. Ведь помимо унификации работы с массивами, строками и неуправляемыми буферами данных они дополнительно легализуют многие unsafe операции. Из доклада мы узнаем: зачем они были…
🔥10👍5
Пульнул на Хабр три старые заметки: про Dictionary<int, T>, про очевидный for или foreach и про inline и throw. В своё время думал, что добавлю туда больше интересного, но за почти год - ничего. Решил закинуть в первозданном виде.
Из интересных наблюдений: заметки писал почти год назад, за это время люди удалили статьи с Хабра, закрыли каналы на Youtube и переписали код .NET. Как быстро летит время.
#статья #память #скорость
Из интересных наблюдений: заметки писал почти год назад, за это время люди удалили статьи с Хабра, закрыли каналы на Youtube и переписали код .NET. Как быстро летит время.
#статья #память #скорость
👍5
Скорость вызова методов #скорость
Давайте вспомним, что такое
Как определить, что будет Call? Тут очень просто. Call будет только в том случае, если метод статический или если работаем со структурой (кроме случаев boxing'a, например, обращения через интерфейс). Ещё есть изменение в .NET 7, которое позволяет не делать callvirt в случаях
Про статические абстрактные методы в интерфейсах не спрашивайте, не знаю как работает.
Во всех остальных случаях будет будет Callvirt:
1. Вызывается виртуальный или абстрактный метод.
2. Вызывается метод интерфеса (со своими нюансами, например, если имплементация всего одна, то будет быстрее).
3. Вызывается переопределённый метод.
Собственно, именно поэтому я часто использую структуры - чтобы повысить производительность. Иногда удачно, иногда - нет.
Прочитать достаточно старые статьи можно вот тут и тут. Прочитать короткое, но свежее, обсуждение можно вот тут. Ну, а моя заметка появилась благодаря вот этому вопросу.
Давайте вспомним, что такое
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. Они это делают.
И не только они, между прочим.
Если кто-то не знал, на C# написана настоящая NoSQL база данных - RavenDB.
Я ей никогда не пользовался, но очень много и вдумчиво читал их код. Для человека, который интересуется скоростью и аллокациями, их кодовая база просто клад.
Множество мелких фишек, не очень очевидных оптимизаций и даже реализаций целых look-free словарей. Кстати первоначальная реализация concurrent lock-free принадлежит некому VSadov - туда тоже рекомендую сходить. Но я так понимаю, что в RavenDB это ещё и обработали напильником под свои нужды.
Короче говоря, если вас спросят, а применяются ли микрооптимизации в реальных работающих приложениях? Можете смело отвечать "да" и называть RavenDB. Они это делают.
И не только они, между прочим.
GitHub
GitHub - ravendb/ravendb: ACID Document Database
ACID Document Database. Contribute to ravendb/ravendb development by creating an account on GitHub.
👍6🔥5
Я люблю эксперименты, в том числе с попытками использовать JS в .NET. Для целей скриптов, разумеется. Всякие там парсеры, лексеры - очень интересно. Недавно набрёл на коллегу, который активно пилит подобное решение.
Мне такие эксперименты очень близки, поскольку лет 5 назад я сам пытался создать движок для исполнения JS на .NET. Естественно, с сильным закосом под крайне быстрое чтение данных с диска, оптимальное формирование AST и прочее. Дело было муторное, застопорилось на попытке качественно покрыть тестами. Их должно быть много (действительно много), что мне в то время было сделать крайне сложно.
А тут, живой код, который растёт, развивается и даже работает. Автор, кстати, ведёт канал в телеге.
#решение
Мне такие эксперименты очень близки, поскольку лет 5 назад я сам пытался создать движок для исполнения JS на .NET. Естественно, с сильным закосом под крайне быстрое чтение данных с диска, оптимальное формирование AST и прочее. Дело было муторное, застопорилось на попытке качественно покрыть тестами. Их должно быть много (действительно много), что мне в то время было сделать крайне сложно.
А тут, живой код, который растёт, развивается и даже работает. Автор, кстати, ведёт канал в телеге.
#решение
Некий Бен Уотсон недавно напомнил о том, как они в Bing шли к .NET 5, почему для них важна производительность и что они скоро планируют начать тестирование .NET 8. Кстати, Bing - ещё один пример живого проекта, где в production применяются подходы написания высокопроизводительного кода на C#.
Бен Уотсон это подтверждает, так как он широко известен своей книгой - Высокопроизводительный код на .NET. Ознакомиться с ней крайне рекомендую. Бен пишет хорошо, не обходит вниманием теорию и примеры. В своё время мне книга очень понравилась.
#книга
Бен Уотсон это подтверждает, так как он широко известен своей книгой - Высокопроизводительный код на .NET. Ознакомиться с ней крайне рекомендую. Бен пишет хорошо, не обходит вниманием теорию и примеры. В своё время мне книга очень понравилась.
#книга
Microsoft News
.NET Performance Delivers Again for Bing, From .NET 5 to .NET 7
.NET has continued to deliver significant performance gains for Bing through multiple releases.
👍7
Продолжая тему того, что оптимизации применяются, причём в разных местах и весьма часто. Причём не хардкорные, а самые что ни на есть простейшие. И не по CPU, а по памяти.
Вот тут ребята из PVS-Studio узнали, что:
1. Надо использовать правильный алгоритм. Это видно на примере их внутреннего кэша, где они складировали в память всё подряд. К кэшу в памяти надо всегда подходить с умом, так как кэш может распухнуть, а его данные вообще попасть в LOH.
2. Одинаковые строки надо пропускать через
3.
4. Итерация по
5. LINQ это красиво, но очень дорого по памяти в горячих местах кода. Во-первых, произойдёт boxing
6. LINQ это штука, которая может выполняться несколько раз. Она ведь с отложенным выполнением. Значит каждый раз, когда мы будем передавать её в различные методы, каждый раз будет выполняться последовательность действий в цепочке выражений. Это дорого по CPU и по памяти. Не надо так. Лучше и дешевле материализовать результат один раз, сложить его в какой-нибудь массив, взятый из
Короче говоря, коллеги впечатлены: на некоторых проектах скорость работы увеличилась более чем на 20%, а пиковое потребление памяти сократилось практически на 70% (цитата из статьи). Что тут сказать? Только пожелать удачи и напомнить, что для некоторых типов задач не работает знаменитое правило о том, что преждевременная оптимизация это плохо. Увы, в некоторых проектах надо сразу писать код с оглядкой на память и CPU. Это окупится трижды, не потребует затрат на исследование возникших проблем и снизит негатив от пользователей.
P.S.: Понимаю, что статья старая, но очень уж показательная. Проблем с памятью не ожидаешь от инструмента, который, вроде бы, должен работать на пользовательских машинах.
#скорость #память
Вот тут ребята из PVS-Studio узнали, что:
1. Надо использовать правильный алгоритм. Это видно на примере их внутреннего кэша, где они складировали в память всё подряд. К кэшу в памяти надо всегда подходить с умом, так как кэш может распухнуть, а его данные вообще попасть в LOH.
2. Одинаковые строки надо пропускать через
string.Intern
- это сильно экономит память. Опять таки, делать это надо осторожно.3.
ToString
создаёт... строку. Причём, иногда, по сложному алгоритму. Если таких вызовов много, то строки аллоцируются, память неумолимо заканчивается, GC не успевает. Не надо так, особенно в горячих местах кода.4. Итерация по
IEnumerable
несколько дорогая по памяти, если расположена в горячем месте. Это актуально для IList
, IReadonlyList
и прочих ICollection
. Просто потому, что IEnumerator
, который возвращается из IEnumerable.GetEnumerator()
, хоть и структура по определению, но размещается в куче по использованию (boxing). Итерируйтесь по классам коллекций, это дешевле. 5. LINQ это красиво, но очень дорого по памяти в горячих местах кода. Во-первых, произойдёт boxing
IEnumerator
как в пункте выше. Во-вторых, сами методы тоже иногда кое-что аллоцируют. Ну и скорость работы несколько ниже простого foreach
. Разверните все LINQ в foreach
в горячих местах кода.6. LINQ это штука, которая может выполняться несколько раз. Она ведь с отложенным выполнением. Значит каждый раз, когда мы будем передавать её в различные методы, каждый раз будет выполняться последовательность действий в цепочке выражений. Это дорого по CPU и по памяти. Не надо так. Лучше и дешевле материализовать результат один раз, сложить его в какой-нибудь массив, взятый из
ArrayPool
, и потом благополучно вернуть обратно.Короче говоря, коллеги впечатлены: на некоторых проектах скорость работы увеличилась более чем на 20%, а пиковое потребление памяти сократилось практически на 70% (цитата из статьи). Что тут сказать? Только пожелать удачи и напомнить, что для некоторых типов задач не работает знаменитое правило о том, что преждевременная оптимизация это плохо. Увы, в некоторых проектах надо сразу писать код с оглядкой на память и CPU. Это окупится трижды, не потребует затрат на исследование возникших проблем и снизит негатив от пользователей.
P.S.: Понимаю, что статья старая, но очень уж показательная. Проблем с памятью не ожидаешь от инструмента, который, вроде бы, должен работать на пользовательских машинах.
#скорость #память
Хабр
Оптимизация .NET приложения: как простые правки позволили ускорить PVS-Studio и уменьшить потребление памяти на 70%
Проблемы с производительностью, такие как аномально низкая скорость работы и высокое потребление памяти, могут быть обнаружены самыми разными способами. Такие не...
👍15🔥2
Не только PVS-Studio (спасибо им за ключ) имеет проблемы с аллокацией памяти. Вот тут JetBrains рассказывают следующее:
1. Надо выбрать хороший алгоритм. В них я разбираюсь плохо, поэтому советов давать не буду: какой-то вариант обхода графа объектов. Важно то, что подбор правильного алгоритма позволил снизить аллокацию с 1.17ГБ до 7.5МБ в секунду. Да, он стал медленнее, но оптимизация это вечная борьба между памятью и CPU.
2. Не нужно создавать миллион
3. Переиспользование коллекций иногда может быть плохой идеей. Например, если
4. Предпочитайте
5. При переходе на структуры, нужно стараться уменьшить количество полей в структуре, чтобы она занимала меньше памяти. Однако, если мы боремся за CPU, то предвычисленные значения предпочтительнее.
6. Обход по массиву структур несколько быстрее обхода массива классов, поскольку данные лежат сильно компактнее и их удобнее читать. На этом эффекте основана производительность некоторых ECS фреймворков для игр.
Коллеги не сделали относительных выводов по данной оптимизации и я их понимаю: приложение вообще отказывалось работать. Тем не менее, я взял максимумы из начала статьи и вынул калькулятор. Итак, увеличение скорости составило больше 90% (с 55 минут до 2 минут), а потребление памяти снизилось на 40% (с 20ГБ до 12ГБ).
#скорость #архитектура #игра #память
1. Надо выбрать хороший алгоритм. В них я разбираюсь плохо, поэтому советов давать не буду: какой-то вариант обхода графа объектов. Важно то, что подбор правильного алгоритма позволил снизить аллокацию с 1.17ГБ до 7.5МБ в секунду. Да, он стал медленнее, но оптимизация это вечная борьба между памятью и CPU.
2. Не нужно создавать миллион
Dictionary
, даже если вам это очень удобно. Это достаточно сложный класс, который внутри себя содержит два массива, которые он ещё и периодически расширяет. Да, он очень удобен, но в горячем месте кода такое удобство может очень больно выстрелить.3. Переиспользование коллекций иногда может быть плохой идеей. Например, если
Dictionary
ранее содержал 20 тысяч элементов, то переиспользовать его не нужно. Это, например, сильно медленнее при очистке (с чем и столкнулись JetBrains). Тут есть два выхода. Либо писать свою коллекцию, которая не очищается, а просто переставляет указатель на первый элемент внутреннего массива. Либо сразу отбрасывать переиспользованную коллекцию, элементов в которой стало больше какого-то предела.4. Предпочитайте
struct
, если объем данных очень большой. Дело в том, что структура не имеет заголовочных данных класса, а значит занимает меньше памяти. В случае JetBrains, объем полезных данных в их классе всего 45 байт. Однако, с учетом заголовка объекта и выравнивания, экземпляр класса занимает 72 байта. Казалось бы копейки, но на большом объеме это будет бить очень больно.5. При переходе на структуры, нужно стараться уменьшить количество полей в структуре, чтобы она занимала меньше памяти. Однако, если мы боремся за CPU, то предвычисленные значения предпочтительнее.
6. Обход по массиву структур несколько быстрее обхода массива классов, поскольку данные лежат сильно компактнее и их удобнее читать. На этом эффекте основана производительность некоторых ECS фреймворков для игр.
Коллеги не сделали относительных выводов по данной оптимизации и я их понимаю: приложение вообще отказывалось работать. Тем не менее, я взял максимумы из начала статьи и вынул калькулятор. Итак, увеличение скорости составило больше 90% (с 55 минут до 2 минут), а потребление памяти снизилось на 40% (с 20ГБ до 12ГБ).
#скорость #архитектура #игра #память
Хабр
Оптимизация dotMemory с использованием dotMemory (и не только...)
dotMemory — это профилировщик памяти для .NET от компании JetBrains. А меня зовут Илья, и я из команды разработки этого инструмента.Хочу поделиться историей классического догфудинга: как мы...
👍20
Бенчмарк в контейнере #хранилища #бенч #анализ
Я тут произвёл замеры своего поделия для S3 с помощью DotMemory в контейнере с Debian. Понял, что про то, как это сделать не писал. Магические строчечки для вашего Docker-файла:
Надо обратить внимание на ключи
Всё делается с помощью консольной версии JetBrains DotMemory. После завершения работы берём файл по адресу
Я тут произвёл замеры своего поделия для S3 с помощью DotMemory в контейнере с Debian. Понял, что про то, как это сделать не писал. Магические строчечки для вашего Docker-файла:
RUN apt-get update -y && apt-get install -y wget && \
wget -O dotMemoryclt.zip https://www.nuget.org/api/v2/package/JetBrains.dotMemory.Console.linux-x64/2022.3.3 && \
apt-get install -y unzip && \
unzip dotMemoryclt.zip -d ./dotMemoryclt && \
chmod +x -R ./dotMemoryclt/*
ENTRYPOINT ./dotMemoryclt/tools/dotmemory start-net-core --temp-dir=./src/dotMemoryclt/tmp --timeout=16m --save-to-dir=./src/dotMemoryclt/workspaces --log-file=./src/dotMemoryclt/tmp/log.txt --trigger-timer=2m ./src/publish/Storage.Benchmark.dll
Надо обратить внимание на ключи
--timeout
(чтобы отключить приложение после указанного времени работы) и --trigger-timer
(время создания snapshot).Всё делается с помощью консольной версии JetBrains DotMemory. После завершения работы берём файл по адресу
--save-to-dir
и открываем в DotMemory.🔥10
Пуллинг массивов #память #статья
Предлагаю прочитать статью от некого Евгения про осторожное использование
Вот какие выводы были сделаны:
1. Пулинг объектов (в том числе массивов) помогает снизить аллокации и нагрузку на GC.
2. Неудачная или неподходящая для конкретного профиля нагрузки реализация пула может испортить производительность.
3. Для небольших массивов, нужных на короткое время, предпочтительно использовать масштабирующийся
4. Для больших массивов желательно использовать пул, созданный через
Предлагаю прочитать статью от некого Евгения про осторожное использование
ArrayPool
в многопоточной среде. Автор рассказал о том, как пул устроен и какие есть способы работать с ним для разных сценариев. Бенчмарки, схемы и разбор диагностик прилагаются. Вот какие выводы были сделаны:
1. Пулинг объектов (в том числе массивов) помогает снизить аллокации и нагрузку на GC.
2. Неудачная или неподходящая для конкретного профиля нагрузки реализация пула может испортить производительность.
3. Для небольших массивов, нужных на короткое время, предпочтительно использовать масштабирующийся
ArrayPool<T>.Shared
.4. Для больших массивов желательно использовать пул, созданный через
ArrayPool<T>.Create
как более вместительный и не разделённый по потокам.Хабр
ArrayPool<T>: подводные камни
Автоматическая сборка мусора упрощает разработку программ, избавляя от необходимости отслеживать жизненный цикл объектов и удалять их вручную. Однако, чтобы сборщик мусора был полезным инструментом, а...
👍8❤5
Инициализация List #память #бенч
А вот мы решили создать List из уже существующего массива. Какой же способ выбрать, если нам важны наносекунды?
Ответ: любой.
Но если наносекунды нам действительно важны, то мы будем выбирать передачу массива в конструктор List'a. Внутри есть попытка каста
Инициализатор, конечно же, является синтаксическим сахаром многократного вызова метода Add (это отчётливо видно в IL).
А вот мы решили создать List из уже существующего массива. Какой же способ выбрать, если нам важны наносекунды?
Ответ: любой.
Но если наносекунды нам действительно важны, то мы будем выбирать передачу массива в конструктор List'a. Внутри есть попытка каста
IEnumerable
к ICollection
, что позволяет создать внутренний массив нужного размера. Именно его расширение является замедляющим фактором и причиной аллокации при вызове банального метода Add.Инициализатор, конечно же, является синтаксическим сахаром многократного вызова метода Add (это отчётливо видно в IL).
👍12👏2
Ещё рекомендую посмотреть видосик о том, как стараются ускорить EF до уровня Dapper. Я, как многие знают, не очень уважаю EF. При этом я понимаю, что в обычной промышленной разработке без ORM тяжело, так как, пока мы строим планы, заказчик быстро и ощутимо меняет ландшафт.
Если кратко, мужчина предлагает функционал предкопилированных выражений для EF.
Подход интересный, который сильно похож на SQL в коде. Но это моё мнение.
Кстати, более подробно про улучшения производительности EF можно прочитать тут.
Программистам-волейболистам спасибо за видео!
#хранилище #лекция
Если кратко, мужчина предлагает функционал предкопилированных выражений для EF.
Подход интересный, который сильно похож на SQL в коде. Но это моё мнение.
Кстати, более подробно про улучшения производительности EF можно прочитать тут.
Программистам-волейболистам спасибо за видео!
#хранилище #лекция
YouTube
Making Entity Framework Core As Fast As Dapper
Check out my courses: https://dometrain.com
Become a Patreon and get source code access: https://www.patreon.com/nickchapsas
Hello, everybody, I'm Nick, and in this video, I will show you how you can use Entity Framework Core's Compiled Queries to achieve…
Become a Patreon and get source code access: https://www.patreon.com/nickchapsas
Hello, everybody, I'm Nick, and in this video, I will show you how you can use Entity Framework Core's Compiled Queries to achieve…
👍3
Быстрый маппер #решение #бенч #скорость #память
А вот маппер. Несколько лет назад я писал статью о том, как вы можете сделать свой маппер на коленке. Сейчас мир изменился, и я хотел бы рассказать про Mapster. Штука годная, быстрая, гораздо лучше, чем AutoMapper. Обратите внимание, что разница между кодом маппинга, который я написал руками, и кодом правильного вызова Mapster'a - минимальная.
Важно. Для тех, кто пользуется Mapster'ом, я бы, при маппинге в коллекции, посоветовал бы брать функцию маппинга, а не использовать встроенную функцию маппинга (видимо там производится поиск необходимого маппера). Понимаю, что можно маппить список в список, но случаи бывают разные, а значит выражение
Код я залил вот сюда, так как его многовато.
Кто-то знает, почему Mapster работает так быстро? Ответ очевиден, но вдруг кто-то не знает. Ответ явно будет в комментах.
P.S.: Я сторонник "ручного" маппинга, если что. Так понятнее, так будет более высокий контроль и так мы экономим наносекунды.
А вот маппер. Несколько лет назад я писал статью о том, как вы можете сделать свой маппер на коленке. Сейчас мир изменился, и я хотел бы рассказать про Mapster. Штука годная, быстрая, гораздо лучше, чем AutoMapper. Обратите внимание, что разница между кодом маппинга, который я написал руками, и кодом правильного вызова Mapster'a - минимальная.
Важно. Для тех, кто пользуется Mapster'ом, я бы, при маппинге в коллекции, посоветовал бы брать функцию маппинга, а не использовать встроенную функцию маппинга (видимо там производится поиск необходимого маппера). Понимаю, что можно маппить список в список, но случаи бывают разные, а значит выражение
TypeAdapter<TIn, TOut>.Map
нужно запомнить.Код я залил вот сюда, так как его многовато.
Кто-то знает, почему Mapster работает так быстро? Ответ очевиден, но вдруг кто-то не знает. Ответ явно будет в комментах.
P.S.: Я сторонник "ручного" маппинга, если что. Так понятнее, так будет более высокий контроль и так мы экономим наносекунды.
👍10❤2