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, 4 days ago
Канал для поиска исполнителей для разных задач и организации мини конкурсов
Last updated 1 month ago
🎉 .NET 9
https://devblogs.microsoft.com/dotnet/announcing-dotnet-9/
https://dotnet.microsoft.com/en-us/download/dotnet/9.0
Вышел .NET 9
В этот релиз вошла фича, придуманная в этом блоге: метод CountBy в LINQ
из мира дотнета: столько лет в rabbitmq клиенте sync over async было и тут видимо под 4.0 rabbitmq переписали и клиента, хорошие новости :)
Green threads & async2
В JVM заехал Project loom — реализация асинхронности на основе virtual threads. Она отличается от привычного нам async/await тем, что синхронный код не отличается от асинхронного вообще, а способ его работы выбирается в рантайме, в зависимости от того, запущен он на обычном или виртуальном потоке.
System.Threading.Lock В .NET 9/C# 13 появился новый примитив синхронизации System.Threading.Lock — managed-реализация блокировки на основе spin-wait + AutoResetEvent. Теперь вместо блокировки вида object o = new object(); lock (o) { ... }, предлагается писать…
System.Threading.Lock
В .NET 9/C# 13 появился новый примитив синхронизации System.Threading.Lock — managed-реализация блокировки на основе spin-wait + AutoResetEvent.
Теперь вместо блокировки вида object o = new object(); lock (o) { ... }
, предлагается писать так:
```
Lock @lock = new Lock();
using (@lock.EnterScope()) { ... }
// или, также поддержана конструкция lock
lock (@lock) { ... }
```
Поводом для добавления нового типа стало желание упростить реализацию лока.
lock
на основе нативного Monitor
использует то же поле из заголовка объекта, что и хэшкод — это приводит к багам и проблемам с производительностью. Вспоминается, однажды баг в локе привёл и к падению рантайма, увы, не нашел сейчас этот issue.
Однако, новый Lock
, в том виде, в каком его планируется добавить в .NET 9, не выглядит проработанным до конца. В основном его проблемы связаны с тем, что было решено поддержать lock statement
для нового типа.
1. Разные локи
Объект Lock
можно присвоить переменной типа object
. Вот так:
private object _sync = new Lock();
В таком случае lock(_sync)
будет использовать Monitor lock
вместо managed lock
. Выходит, что под новый Lock
может зайти два потока сразу — один честно, через managed блокировку, второй — ошибочно, через Monitor
.
Чтобы избежать этого бага предусмотрен warning компилятора. Если решите использовать Lock
, рекомендую сразу включить <WarningsAsErrors>CS9216</WarningsAsErrors>
. Warning отлавливает не все варианты скастить Lock
к object
, например можно скастить через generic-метод вида object ToObject<T>(T obj) => obj;
.
CS9216 : A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor\-based locking in 'lock' statement.
2. Поддержка других видов блокировок в lock
Изначально планировалась возможность расширения конструкции lock
произвольными типами. Например — lock(SpinLock)
, lock (Semaphore)
, lock(MyDistributedLock)
... — любые типы, имеющие методы Enter/Exit, или специальный интерфейс для блокировки. Но в финальную версию вошла поддержка только типа System.Threading.Lock
, а расширяемость оставлена на будущее.
При желании можно обмануть компилятор и всё же подсунуть ему свою реализацию (также можно сделать и с методами класса Monitor
```
namespace System.Threading {
public class Lock {
public Scope EnterScope() {
Console.WriteLine("EnterScope");
return default;
}
public ref struct Scope {
public void Dispose() => Console.WriteLine("Dispose");
}
}
}
```
3. Отсутствие аналогов Monitor.Wait/Pulse/PulseAll
Оставлено на будущее. API proposal: ConditionVariable
==========
Итого, чтобы избежать багов с новым типом Lock
лучше сразу включить <WarningsAsErrors>CS9216</WarningsAsErrors>
, до того, как кто-нибудь попробует им воспользоваться.
API proposal: https://github.com/dotnet/runtime/issues/34812
C# 13 release notes: https://devblogs.microsoft.com/dotnet/csharp-13-explore-preview-features/#lock-object
C# language proposal (наиболее подробный):
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/lock-object
https://github.com/dotnet/csharplang/blob/main/proposals/lock-object.md
@epeshkblog *?*? Поддержать канал ? ?**
GitHub
Add first class System.Threading.Lock type · Issue #34812 · dotnet/runtime
Background and Motivation Locking on any class has overhead from the dual role of the syncblock as both lock field and hashcode et al. (e.g. #34800) Adding a first class lock type that didn't a...
Очень интересная статья про AVX512 - в частности как он был реализован AMD в ядре Zen4 и в Zen5 mobile (две операции по 256 бит) и как его сделали в ядре Zen5 (честные 512 бит). Но, есть конечно и физика, от которой никуда не деться
Therefore, this behavior is consistent with the earlier observation that Zen5 can run AVX512 at full clock speed provided there is thermal headroom. Somehow Zen5 manages to keep all that extra hardware on standby and can wake it up instantly.
Но очень удивлён как это реализовано в Intel процессорах (далее мой перевод):
Для процессоров Intel эти переходы [от обычного кода к коду с AVX512] обрабатываются в два этапа:
1) При переходе от кода низкой интенсивности (low-intensity) к коду высокой интенсивности (high-intensity), код высокой интенсивности работает с резко сниженной пропускной способностью, чтобы уменьшить его интенсивность.
2) После длительного периода в ~50 000 циклов код с более высокой интенсивностью переключается на полную пропускную способность.
Как упоминалось ранее, процессоры Intel не могут запускать AVX512 на полной скорости, так как они выйдут из строя [ниже в статье есть упоминание про Vdroop и я пока не понял - то ли напряжение падает то ли наоборот подскакивает]. Поэтому, прежде чем он сможет запустить AVX512, ему сначала нужно снизить тактовую частоту.
Снижения тактовой частоты выполняется тактовым генератором и регулятором напряжения и это занимает время ~50 000 циклов. Также требуется дополнительные аппаратные модули, которые включаются и используются только с 512-битными инструкциями.
...
На более высоких тактовых частотах включены только нижние 128 бит 512-битного оборудования. На этой [полной] скорости включение верхних 384 бит вызовет [повышение?] vdroop, которое может вывести ядро из строя. Только на более низких скоростях могут быть включены все 512 бит. Но во время ожидания, пока процессор переключается на более низкую частоту - код может выполнять 512 битные инструкции, используя нижние 128 бит, что занимает в 4 раза больше времени, но это лучше чем вообще ничего не делать.
Вместо приостановки выполнения на ~50 000 циклов, процессоры Intel разбивают более широкие инструкции и "многократно перекачивают" (multi-pump) их в модули, которые уже включены и готовы к использованию на текущей тактовой частоте.
(конец цитаты)
?♂️ походу костыли не только в софте бывают :))) Буду искать подробности ещё. #simd
Принёс книжку по concurrency
Мифы .NET: ValueTask
Миф: ValueTask
полезен только если метод чаще всего завершается синхронно
Реальность: ValueTask позволяет избежать аллокаций, даже если метод выполняется асинхронно.
Для этого нужно пометить асинхронный метод, возвращающий ValueTask атрибутом:
[AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder))]
для ValueTask
[AsyncMethodBuilder(typeof(PoolingAsyncValueTaskMethodBuilder<>))]
для ValueTask<T>
В старых версиях .NET была env переменная, включающая пулинг глобально, но сейчас это уже не работает.
ValueTask
может оборачивать переиспользуемый объект IValueTaskSource
, умеющий сигнализировать об окончании асинхронного ожидания. Примеры таких объектов: - AsyncOperation<T>
в System.Threading.Channels
- ManualResetValueTaskSourceCore<T>
— структура с логикой для упрощения создания своей реализации IValueTaskSource
. По сути — переиспользуемый аналог TaskCompletionSource
- SemaphoreCompletionSource
в ConcurrencyToolkit
Возможность переиспользования накладывает ограничение — ValueTask
должен await
-иться только один раз. Точнее, метод .GetResult()
должен вызываться ровно один раз, т.к. именно в нём реализуется логика по освобождению IValueTaskSource
для переиспользования.
Если ValueTask
не await
-ится, и на нём не вызывается .GetResult()
— это тоже плохо. Значит IValueTaskSource
не будет переиспользоваться
————
Также, в отличие от обычного Task
, ValueTask
не реализует интерфейс IDisposable
. Это полезно, если результат асинхронного метода предполагается использовать в using
.
Пример:
```
struct LockHolder : IDisposable;
Task LockAsync();
ValueTask ValueLockAsync();
using (LockAsync()) // баг, диспоузится Task
using (ValueLockAsync()) // ошибка компиляции, ValueTask не IDisposable
using (await ValueLockAsync()) // OK
```
https://devblogs.microsoft.com/dotnet/how-async-await-really-works/#and-valuetasks @epeshkblog *?*? Поддержать канал ? ?**
Недокументированная особенность Dictionary и HashSet
Енумераторы Dictionary
и HashSet
перечисляют элементы в порядке добавления, если из коллекции не было удалений.
```
var hs = new HashSet { 1, 4, 2, 5, 3 };
Console.WriteLine(string.Join(", ", hs));
// output: 1, 4, 2, 5, 3
```
Это недокументированная особенность реализации. Хэш-таблица внутри Dictionary
и HashSet
организована в виде двух массивов: _buckets
и _entries
. Значения хранятся в массиве _entries
, который заполняется от начала к концу, а при увеличении размера коллекции копируется как есть.
При удалении в массиве _entries
образуется пустое место, которое будет занято новым элементом, что нарушит упорядоченность.
Хоть возможность и недокументированная, она используется и в BCL, например в реализации нового LINQ-метода .CountBy()
. Даже есть тест на случай, если устройство Dictionary
изменится в будущем.
Но кажется, поменять реализацию будет непросто — эту особенность наверняка часто используют не подозревая, что это лишь деталь реализации. Однако лучше не полагаться на это в критичном коде, только на свой страх и риск.
Старый не-generic Hashtable
такой особенностью не обладает — эта реализация хэш-таблицы использует один массив и для элементов, и для адресации: элементы располагаются в соответствии с их хэш-кодами, а не по порядку добавления, и перечисляются в том же порядке, что и хранятся.
@epeshkblog *?*? Поддержать канал и выход новых ХАБР статей ? ?**
GitHub
[API Proposal]: Linq CountBy method · Issue #77716 · dotnet/runtime
Draft implementation: alternative design 2 Background and motivation Currently, it is not so easy to count occurrences of IEnumerable<T> elements with existing LINQ methods in C#. var arr = n...
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, 4 days ago
Канал для поиска исполнителей для разных задач и организации мини конкурсов
Last updated 1 month ago