C# Heppard

Description
25 способов эффективно использовать .NET

Поддержать канал можно тут: https://sponsr.ru/sharp_heppard
Advertising
We recommend to visit
HAYZON
HAYZON
6,053,581 @hayzonn

لا اله الا الله محمد رسول الله

👤 𝐅𝐨𝐮𝐧𝐝𝐞𝐫: @Tg_Syprion
🗓 ᴀᴅᴠᴇʀᴛɪsɪɴɢ: @SEO_Fam
Мои каналы: @mazzafam

Last updated 3 weeks, 1 day ago

Architec.Ton is a ecosystem on the TON chain with non-custodial wallet, swap, apps catalog and launchpad.

Main app: @architec_ton_bot
Our Chat: @architec_ton
EU Channel: @architecton_eu
Twitter: x.com/architec_ton
Support: @architecton_support

Last updated 2 weeks, 2 days ago

Канал для поиска исполнителей для разных задач и организации мини конкурсов

Last updated 1 month ago

1 month, 4 weeks ago

Бесплатные Rider и WebStorm

Ого, решительно поддерживаю! Обещают, что приложение будет полностью функциональным и ни чем не отличаться от платной версии. Хорошее решение для пет-проектов и не только.

Злые языки утверждают, что такой шаг со стороны чехов - последствия снижения качества, низких продаж и жаркого дыхания VS и VSCode в спину Rider'у. Но я желаю парням успехов.

Ещё интернетах пишут, что эти IDE уже можно скачать через некий uTorrent. Не знаю, что это за приложение - надо попробовать. Увы, официальный Toolbox что-то перестал скачивать обновления - видимо, высокая нагрузка.

P.S.: И вот ещё новая информация, о блокировании пользователей, которые уже оплатили лицензии.

4 months, 2 weeks ago

Работа с ArrayPool и MemoryPool #память

Пул массивов - классная штука, но есть проблема. И даже две.

Первая проблема. Когда мы пытаемся получить ArrayPool<T>.Shared.Rent массив размером, допустим, в 4 элемента, мы получаем массив размером в 16 элементов. Если запросим 16, то получим 16, а вот если нам нужно 17 элементов, то мы получим аж 32. Таким образом, при запросе массива, мы всегда получаем массив размером не менее нужного. Это сделано специально, чтобы не аллоцировать большое количество массивов разного размера.

Соответственно, при попытке итерироваться по полученному массиву, мы можем столкнуться с пустыми элементами, либо элементами, которые содержат предыдущие данные (очистка массива перед возвратом в пул это право, а не обязанность потребителя).

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

var pool = ArrayPool<int>.Shared; var array = pool.Rent(length); var segment = new ArraySegment<int>(array, 0, length);

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

Во-вторых, мы можем воспользоваться Span. Это отличный вариант, когда мы передаём кусочек массива в методы, которые не являются async. Напомню, нам запрещено работать с ref struct в асинхронных методах.

… var span = array.AsSpan(..length);

В-третьих, можно использовать Memory - структурой, которая так же как и ArraySegment, указывает на область памяти. Конечно, при данном подходе, логичнее использовать не ArrayPool, а MemoryPool, который работает примерно так же, как и ArrayPool.

var pool = MemoryPool<int>.Shared; using var memoryOwner = pool.Rent(length); var memory = memoryOwner.Memory[..length];

Memory это обычная структура, а значит нет никаких проблем передавать её в async методы и не думать в них о том, какой же реальный размер памяти мы используем. Напомню, что взаимодействие с Memory осуществляется через Span (memory.Span).

Вторая проблема при работе с ArrayPool - возврат использованного массива. Когда мы закончили работу с массивом из пула, логично было бы вернуть его в пул в том же методе, в котором мы его получили. Более того, мне кажется, что это правильное решение с точки зрения архитектуры.

```
var pool = ArrayPool.Shared;
var array = pool.Rent(length);

DoSomething(array.AsSpan(..length));

pool.Return(array);
```

Если мы обратим внимание на использование MemoryPool, то он возвращает не Memory, а IMemoryOwner, что как бы намекает: есть владелец памяти, а есть методы, которые память используют. Передавая в методы использования и Memory, и IMemoryOwner’a, мы делаем утверждение, что теперь другой метод является владельцем области памяти, а значит именно он ответственен за её очистку.

```
var pool = MemoryPool.Shared;
var memoryOwner = pool.Rent(length);
var memory = memoryOwner.Memory[..length];

DoSomething(memory, memoryOwner);
```

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

Другие способы (ArraySegment или Span) такой конструкцией не обладают, и мы должны самостоятельно придумывать костыли для возврата массива в пул. Например, можно написать микс ArraySegment’a с IMemoryOwner, который обладает возможностью возврата массива в пул при вызове Dispose. Его код будет в комментариях. А можно ещё и вот так.

Используя подобный велосипед, вы сможете передавать в методы-потребители структуру PooledArray<T> и в нужном месте вызывать Dispose, который вернёт массив в пул. В принципе, весьма неплохое решение. Если смотреть на бенчмарк всего сценария, то получается даже быстро.

4 months, 3 weeks ago

TryGetNonEnumerated #память

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

Напомню, что первоначально List<T> создаётся с внутренним массивом размера 0. При последующем добавлении элементов происходит проверка, и, если места не хватает, внутренний массив расширяется на свой размер, умноженный на 2. «Расширение», в данном случае, означает, что создаётся новый массив, а содержимое старого массива копируется в новый. Таким образом, если мы заранее создадим List с внутренним массивом в 200 элементов, то мы избежим аллокаций шести массивов - это весьма солидно .

Однако, увы, некоторые методы возвращают IEnumerable<T>, из которого весьма проблематично узнать размер. Да, за IEnumerable может скрываться любая из коллекций, имплементирующая ICollection<T>, и тогда проблем с выяснением первоначального размера нашей коллекции нет. Но что если нам пришёл результат чего-то вот такого?

```

_data = array // первоначальный массив
.Skip(1)
.Take(Count / 2)
.Order()
.Select(static i => i * i % 10 == 0 ? "да" : "нет");

```

Это точно не ICollection<string>, то есть выяснить размер мы не сможем. Вернее, всё-таки сможем. Если заглянуть в недра .NET, то мы узнаем, что это некий Enumerable.SelectIPartitionIterator, который, на наше счастье, реализует внутренний интерфейс IIListProvider. Чтобы попытаться воспользоваться его методом GetCount, нам поможет метод TryGetNonEnumeratedCount, который появился аж в .NET 6.

В нашем случае он может быть применён вот так:

```

var capacity = _data.TryGetNonEnumeratedCount(out var count)
? count
: ваша_эвристическая_константа;

var list = new List(capacity);
list.AddRange(_data);

```

Почему этот подход не используется в конструкторе того-же List’a (который принимает IEnumerable) и в его же методе AddRange - загадка. Наверное, у коллег пока просто не дошли руки.

P.S.: Для желающих посмотреть, что метод TryGetNonEnumerated действительно ничего не перебирает, а просто возвращает значение - в комментариях есть бенчмарк.

We recommend to visit
HAYZON
HAYZON
6,053,581 @hayzonn

لا اله الا الله محمد رسول الله

👤 𝐅𝐨𝐮𝐧𝐝𝐞𝐫: @Tg_Syprion
🗓 ᴀᴅᴠᴇʀᴛɪsɪɴɢ: @SEO_Fam
Мои каналы: @mazzafam

Last updated 3 weeks, 1 day ago

Architec.Ton is a ecosystem on the TON chain with non-custodial wallet, swap, apps catalog and launchpad.

Main app: @architec_ton_bot
Our Chat: @architec_ton
EU Channel: @architecton_eu
Twitter: x.com/architec_ton
Support: @architecton_support

Last updated 2 weeks, 2 days ago

Канал для поиска исполнителей для разных задач и организации мини конкурсов

Last updated 1 month ago