В прошлый раз я рассказывал, что методы библиотек .NET приходят уже с готовым машинным кодом в формате ReadyToRun (R2R), поэтому JIT-компиляция при первом вызове им не нужна. А можно ли так же заранее скомпилировать свой код? Можно 👇
🛠 Как это сделать
Проект надо опубликовать, то есть собрать для поставки командой
dotnet publish, и добавить параметр PublishReadyToRun📤Но ведь JIT компилирует IL под процессор, на котором программа выполняется прямо сейчас. А под какой процессор компилировать заранее?
Компилятору приходится компилировать так, чтобы итоговый машинный код подошёл под любой процессор нужной платформы. Платформа же указывается в параметре
--runtime (сокращённо -r):dotnet publish -r linux-x64 -p:PublishReadyToRun=true
Такая публикация доступна с .NET Core 3.0
Теперь наш
Hello() ведёт себя так же, как Console.WriteLine в прошлом посте: если вызвать его один раз, в сводке JIT он не будет упоминаться, потому что работает готовый код и JIT его не компилировал. Если же вызывать его достаточно часто, тогда JIT всё-таки перекомпилирует этот собранный заранее код, ведь он был оптимизирован лишь по виду кода, а не по профилю работы:Program:Hello() [Instrumented Tier1]
Program:Hello() [Tier1]
То есть JIT никуда не делся, просто работы у него стало поменьше
⏰ А стало ли быстрее?
Документация прямо говорит, что
ReadyToRun ускоряет старт приложений, в которых много своего кода, давай это проверим👇 Можно написать программу из 5000 маленьких методов, в каждом несколько арифметических действий и одно условие. Каждый метод вызывается один раз
Cводка JIT показала вот такой результат:
компиляций старт
обычная сборка 5004 68 мс
ReadyToRun 2 16 мс
В обычной сборке JIT при старте компилирует все 5000 методов, а ещё
Main, метод, который их по очереди вызывает, и два метода библиотек .NET. С ReadyToRun остаются только эти два библиотечных, а программа стартует в 4 раза быстрее 🚀
💸 Чем за это платим
Если опубликовать эту программу без ReadyToRun, её .dll весит 440 КБ, а с ReadyToRun — 1038 КБ, что примерно в 2,4 раза больше. Это потому, что внутри теперь лежат и IL, и готовый машинный код. Да, IL никуда не делся, потому что он всё равно понадобится, чтобы JIT мог перекомпилировать горячие методы
🅰️ Что с этим делать
🟢 ReadyToRun компилирует под любой процессор платформы из
--runtime, а JIT — под конкретный процессор, на котором программа работает прямо сейчас🟢 R2R избавляет JIT от работы на старте, и выигрыш тем заметнее, чем больше в приложении своего кода
🟢 Платим за это размером файла
А можно ли пойти дальше и убрать JIT совсем? Можно, и об этом расскажу в следующий раз 👉
🧑💻dp🥁
#dotnet #csharp #инженерныештучки #heavywednesday
