JIT
Среди всех областей .NET наиболее значимым является JIT-компилятор (Just-In-Time, «точно в срок»). Каждое приложение .NET, будь то небольшой консольный инструмент или крупномасштабная корпоративная служба, в конечном счёте использует JIT-компилятор для преобразования кода на промежуточном языке (IL) в оптимизированный машинный код. Любое улучшение качества кода, генерируемого JIT-компилятором, оказывает комплексное воздействие, повышая производительность всей экосистемы без необходимости вносить изменения в собственный код или даже перекомпилировать C#. И в .NET 10 таких улучшений предостаточно.
Деабстракция
Как и во многих других языках, в .NET исторически наблюдался «штраф за абстракцию» — дополнительные выделения памяти и косвенная адресация, которые могут возникать при использовании высокоуровневых языковых функций, таких как интерфейсы, итераторы и делегаты. С каждым годом JIT-компилятор всё лучше оптимизирует уровни абстракции, позволяя разработчикам писать простой код и при этом получать высокую производительность. .NET 10 продолжает эту традицию. В результате идиоматический C# (с использованием интерфейсов, циклов foreach , лямбда-выражений и т. д.) работает почти так же быстро, как тщательно продуманный и отлаженный вручную код.
Выделение стека объектов
Одним из самых интересных направлений в области деабстракции в .NET 10 является расширенное использование анализа выхода за пределы метода для выделения объектов в стеке. Анализ выхода за пределы метода — это метод компилятора, который позволяет определить, выходит ли объект, выделенный в методе, за пределы этого метода, то есть доступен ли этот объект после возврата из метода (например, сохранён ли он в поле или возвращён вызывающей стороне) или используется каким-то образом, который среда выполнения не может отследить в рамках метода (например, передан неизвестному вызываемому объекту). Если компилятор может доказать, что объект не выйдет за пределы метода, то время жизни этого объекта будет ограничено методом, и его можно будет выделить в стеке, а не в куче. Выделение в стеке обходится гораздо дешевле (простое увеличение указателя для выделения и автоматическое освобождение при выходе из метода) и снижает нагрузку на сборщик мусора, поскольку объект не нужно отслеживать сборщику мусора. В .NET 9 уже была реализована ограниченная поддержка анализа выхода за пределы метода и выделения в стеке; в .NET 10 эта поддержка значительно расширена.
public partial class Tests
{
[Benchmark]
[Arguments(42)]
public int Sum(int y)
{
Func<int, int> addY = x => x + y;
return DoubleResult(addY, y);
}
private int DoubleResult(Func<int, int> func, int arg)
{
int result = func(arg);
return result + result;
}
}
If we just run this benchmark and compare .NET 9 and .NET 10, we can immediately tell something interesting is happening.
Method
Runtime
Mean
Ratio
Code Size
Allocated
Alloc Ratio
Sum
.NET 9.0
19.530 ns
1.00
118 B
88 B
1.00
Sum
.NET 10.0
6.685 ns
0.34
32 B
24 B
0.27
и солнце б утром не вставало, когда бы не было меня
Вот всё мне нравится в прогрессе Корки! Одно не пойму — что же такого кривого надо было написать в .NET FW, что ни одна из этих оптимизаций не была там применена?
Мелкософту понадобилась вся мощь "автоматического развешивателя спагетти на уши", чтобы хоть как-то сдвинуть интыпрайз в сторону "мы наш, мы новый кор построим".
Хотя куда более логичным решением было бы мягко перестраивать кишки FW, чтобы можно было вводить оптимизации и даже менять платформу.
Ну вот купили они Жабьи кишки (JRE), что-то там накрутили, выкатили .NET — по факту просто "запускатор + куча либ" для MSIL поверх венды. Есессно, с каким-то gate/proxy к Win32 (pinvoke). Ну что такого можно было там написать Windows-only, чего нельзя было бы вырезать и перенести на линукс? Или внедрить всякие SSE/AVX.
Другими словами, зачем понадобилось городить аж целую несовместимую систему вместо улучшения существующей? Хоже того — Кора до сих пор страдает отсутствием важных технологий — та же WPF или WinForms. Про ошибки самой Коры и говорить не буду — стало просто принятым иметь кучу багов в любом релизе.
Собственно, я потому и пишу до сих пор в FW/WPF, что мне не упёрлись эксперименты на себе самом. Так мало я страдаю как "бесплатный пациент", мой же код ещё в продакшен нести! Я что, должен там позориться "извините, индусы ещё не добрались до этих багов, так что сервер будет периодически падать"?? Увольте, мне такой забагованый, дилетантский прогресс не нужен. Лучше медленно и надёжно, чем "анализ выхода за пределы метода для выделения объектов в стеке" и банально неработающая кнопка.
Ну изначально там библиотеки были написаны на использование джитом. А там главное скорость компиляции, а не выполнения.
Вообще Core был нужен прежде всего для .Net Native. Это и Windows Mobile, XBOX итд
А там уже нужно было дробить библиотеки. Во многие библиотеки были вшиты нативные dll, которые не совместимы с arm.
Ну и тогда еще не было обрезания.
До линукса было еще ооочень далеко. Больше речь шла о Windows на ARM
и солнце б утром не вставало, когда бы не было меня
B>Вот всё мне нравится в прогрессе Корки! Одно не пойму — что же такого кривого надо было написать в .NET FW, что ни одна из этих оптимизаций не была там применена?
Это была совершенно другая команда. Люди. Программисты, если угодно.
B>Другими словами, зачем понадобилось городить аж целую несовместимую систему вместо улучшения существующей?
См. объяснение выше. Это другая команда, более грамотная, с бОльшим уровнем знаний и умений.
B> Я что, должен там позориться "извините, индусы ещё не добрались до этих багов, так что сервер будет периодически падать"??
В команде рантайма почти нет индусов. И вообще процент белого населения меня удивил
PS: чтоб два раза не вставать. Если у тебя кака "какая-то бага, до которой индусы не добрались" — иди сюда: https://github.com/dotnet/runtime
Запускай магическую команду "git clone", собирай дебаг билд, фикси баг. Заодно и поймешь, почему "индусы не добрались". Очень часто то, что люди принимают за "мелкий баг", требует весьма нетривиального теста. А иногда и исправление неочевидно.
DATAS еще в 9-ке был. Сомнительная фича, если честно. С одной стороны, вроде как нужна для cloud, чтобы не balloon'ить память для лучшей утилизации. С другой — как раз именно в cloud использование подобной эвристики приводит не к увеличению, а к уменьшению производительности. Иными словами, хорошо тюненые сервисы от DATAS скорее проиграют, чем выиграют.