На прошлой неделе вышел .NET Core 3.0 (Preview 6). В него вошли обновления компиляции сборок для улучшения запуска, улучшения оптимизации приложений по размеру с улучшениями компоновщика и EventPipe. Мы также выпустили новые образы Docker для Alpine на ARM64.
Скачать .NET Core 3.0 (Preview 6) на Windows, macOS и Linux.
Заметки выпуска опубликованы в dotnet/core. Различия API между Preview 5 и 6 также доступны.
ASP.NET Core и EF Core также выпущены на прошлой неделе.
Если вы пропустили, изучите обновления .NET Core 3.0 (Preview 5) прошлого месяца.
Обновления WPF и Windows Forms
Команда WPF полностью закончила процесс публикации большей части кода WPF на GitHub. На самом деле, они просто опубликовали исходники пятнадцати сборок. Для тех, кто знаком с WPF, названия сборок должны быть очень знакомы.
В некоторых случаях тесты все еще находятся в бэклоге и должны быть опубликованы в или до 3.0 GA. Тем не менее, наличие всего этого кода должно позволить сообществу WPF в полной мере участвовать во внесении изменений в WPF. После прочтения некоторых проблем с GitHub становится очевидным, что у сообщества есть собственный бэклог новинок, которые хочется реализовать. Что думаете о темной теме?
Образы Alpine Docker
Образы Docker теперь доступны как для .NET Core, так и для ASP.NET Core на ARM64. Ранее они были доступны только для x64.
Следующие образы могут быть использованы в Dockerfile
, или с docker pull
, как показано ниже:
docker pull mcr.microsoft.com/dotnet/core/runtime:3.0-alpine-arm64v8
docker pull mcr.microsoft.com/dotnet/core/aspnet:3.0-alpine-arm64v8
Улучшения Event Pipe
Event Pipe теперь поддерживает мультисессиональность.
Добавлены новые счетчики производительности:
- % Time in GC
- Gen 0 Heap Size
- Gen 1 Heap Size
- Gen 2 Heap Size
- LOH Heap Size
- Allocation Rate
- Number of assemblies loaded
- Number of ThreadPool Threads
- Monitor Lock Contention Rate
- ThreadPool Work Items Queue
- ThreadPool Completed Work Items Rate
Присоединение Profiler теперь реализовано с использованием той же инфраструктуры Event Pipe.
Прочитайте Игру со счетчиками от Дэвида Фаулера, чтобы получить представление о том, что вы можете сделать с помощью event pipe, чтобы провести собственное исследование производительности или просто отслеживать состояние приложения.
Прочитайте dotnet-counters чтобы установить инструмент dotnet-counters.
Оптимизируйте свои приложения .NET Core с помощью образов ReadyToRun
Вы можете улучшить время запуска приложения .NET Core, скомпилировав сборки приложений в формате ReadyToRun (R2R). R2R — это форма опережающей компиляции (AOT).
Бинарные файлы в формате R2R улучшают производительность при запуске, уменьшая объем работы, которую JIT должен выполнять во время загрузки приложения. Бинарные файлы содержат машинный код, аналогичный тому, который генерирует JIT, что дает JIT немного отдыха, когда производительность важнее всего (при запуске). Бинарные файлы в R2R формате больше, потому что они содержат как код на промежуточном языке (IL), который все еще необходим для некоторых сценариев, так и машинную версию того же кода для улучшения запуска.
R2R поддерживается .NET Core 3.0. Его нельзя использовать с более ранними версиями .NET Core.
Цифры по производительности сэмплов
Далее приведены цифры, показывающие производительность сэмплов приложений WPF. Приложение было опубликовано как автономное и не использовало компоновщик сборки (рассмотрено позже в этой статье).
IL-only приложение:
- Время запуска: 1.9 секунды
- Использование памяти: 69.1 MB
- Размер приложения: 150 MB
С образами ReadyToRun:
- Время запуска: 1.3 секунды.
- Использование памяти: 55.7 MB
- Размер приложения: 156 MB
Подробнее о ReadyToRun образах
Вы можете скомпилировать R2R как библиотеки, так и бинарные файлы приложений. В настоящее время библиотеки могут быть скомпилированы в R2R только как часть приложения, а не для доставки в виде пакета NuGet. Мы хотели бы получить больше отзывов о том, важен ли этот сценарий.
Компиляции сборок AOT уже давно доступны как концепция для .NET, возвращаясь к .NET Framework и NGEN. Ключевой недостаток NGEN заключается в том, что компиляция должна выполняться на клиентских машинах с использованием инструмента NGEN. Невозможно сгенерировать образы NGEN как часть сборки вашего приложения.
Теперь .NET Core. Он приходит с crossgen, который производит машинные образы в новом формате ReadyToRun. Название описывает его основную ценность, заключающуюся в том, что эти машинные образы могут быть созданы как часть вашей сборки и «готовы к запуску» без какой-либо дополнительной работы на клиентских машинах. Это серьезное улучшение, а также важная победа в борьбе с изменением климата.
С точки зрения совместимости образы ReadyToRun аналогичны сборкам IL с некоторыми ключевыми отличиями.
- IL сборки содержат только IL код. Они могут работать в любой среде выполнения, которая поддерживает заданную целевую инфраструктуру для этой сборки. Например,
netstandard2.0
сборка может работать на .NET Framework 4.6+ и .NET Core 2.0+, на любой поддерживаемой операционной системе (Windows, macOS, Linux) и архитектуре (Intel, ARM, 32-разрядная, 64-разрядная). - Сборки R2R содержат IL и собственный код. Они скомпилированы для определенной минимальной версии среды выполнения .NET Core и окружения среды выполнения (RID). например, сборка
netstandard2.0
может быть R2R-скомпилирована для .NET Core 3.0 и Linux x64. Она будет использоваться только в этой или совместимой конфигурации (например, .NET Core 3.1 или .NET Core 5.0 в Linux x64), поскольку она содержит собственный код, который можно использовать только в этой среде выполнения.
Инструкции
ReadyToRun компиляция доступна только для публикации. Превью-версия была выпущена в .NET Core 3.0 (Preview 5).
Чтобы включить компиляцию ReadyToRun, вам необходимо:
- Установить значение свойства
PublishReadyToRun
какtrue
. - Опубликовать с использованием точного
RuntimeIdentifier
.
Примечание. Когда сборки приложения компилируются, создаваемый собственный код зависит от платформы и архитектуры (поэтому при публикации необходимо указывать действительный RuntimeIdentifier).
Вот пример:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<PublishReadyToRun>true</PublishReadyToRun>
</PropertyGroup>
</Project>
И публикация с использованием следующей команды:
dotnet publish -r win-x64 -c Release
Примечание: RuntimeIdentifier
может быть установлен в файле проекта.
Примечание: ReadyToRun в настоящее время поддерживается только для автономных приложений. Он будет добавлен для зависимых от фреймворка приложений в более позднем анонсе.
Машинную генерацию символов можно включить, установив для свойства PublishReadyToRunEmitSymbols
значение true
. Вам не нужно создавать машинные символы для целей отладки. Эти символы полезны только для целей профилирования.
В настоящее время SDK поддерживает способ исключения определенных сборок из компилирования в образы ReadyToRun. Это может быть полезно в тех случаях, когда сборки не нуждаются в оптимизации для повышения производительности. Исключение сборок в этом случае может помочь уменьшить размер приложения. В случае когда компилятору ReadyToRun не удается скомпилировать определенную сборку, решением также может быть ее исключение.
Исключение выполняется с помощью группы элементов PublishReadyToRunExclude:
<ItemGroup>
<PublishReadyToRunExclude Include="FilenameOfAssemblyToExclude.dll" />
</ItemGroup>
Кроссплатформенные/архитектурные компиляции
Компилятор ReadyToRun пока не поддерживает кросс-таргетинг. Нужно компилировать по заданной цели. Например, если вам нужны образы R2R для Windows x64, вам нужно выполнить команду публикации в этой среде.
Исключения:
- Windows x64 может быть использована для компиляции образов Windows ARM32, ARM64, and x86.
- Windows x86 может быть использована для компиляции образов Windows ARM32.
- Linux x64 может быть использована для компиляции образов Linux ARM32 and ARM64.
Компоновка сборок
NET core 3.0 SDK поставляется с инструментом, который может уменьшить размер приложений путем анализа IL и исключения неиспользуемых сборок.
С .NET Core всегда можно было публиковать автономные приложения, которые включают в себя все необходимое для запуска вашего кода, без необходимости устанавливать .NET на цель развертывания. В некоторых случаях для работы приложения требуется только небольшое подмножество фреймворка, и его можно было бы сделать значительно меньшим за счет включения только используемых библиотек.
Мы используем компоновщик IL для сканирования IL вашего приложения, чтобы определить, какой код на самом деле требуется, а затем исключить неиспользуемые библиотеки фреймворков. Это может значительно уменьшить размер некоторых приложений. Как правило, небольшие консольные приложения, подобные инструментам, получают наибольшую выгоду, поскольку они зачастую используют небольшие подмножества фреймворка и обычно хорошо поддаются обрезке.
Чтобы использовать этот инструмент, установите PublishTrimmed=true
в своем проекте и опубликуйте автономное приложение:
dotnet publish -r <rid> -c Release
Выходные данные публикации будут включать подмножество библиотек инфраструктуры, в зависимости от того, какие вызывает код приложения. Для приложения helloworld компоновщик уменьшает размер с ~68 МБ до ~28 МБ.
Приложения или фреймворки (включая ASP.NET Core и WPF), в которых используются рефлексия или связанные динамические функции, часто ломаются при обрезке, поскольку компоновщик не знает об этом динамическом поведении и обычно не может определить, какие типы фреймворков потребуются для рефлексии во время выполнения. Чтобы обрезать такие приложения, вы должны сообщить компоновщику о любых типах, необходимых для рефлексии в вашем коде и в любых пакетах или средах, от которых вы зависите. Обязательно протестируйте свои приложения после обрезки.
Для получения дополнительной информации о IL Linker см. документацию или посетите репозиторий mono/linker.
Примечание: В предыдущих версиях .NET Core, ILLink.Tasks поставлялся как внешний пакет NuGet и предоставлял большую часть той же функциональности. Он больше не поддерживается — обновите до последней версии 3.0 SDK.
Совместное использование компоновщика Linker и ReadToRun
Компоновщик Linker и компилятор ReadyToRun могут использоваться для одного и того же приложения. В целом, компоновщик делает ваше приложение меньше, а затем готовый к запуску компилятор снова сделает его немного больше, но со значительным выигрышем в производительности. Стоит протестировать различные конфигурации, чтобы понять влияние каждого варианта.
Примечание: dotnet/sdk #3257 предотвращает совместное использование компоновщика и ReadyToRun для приложений WPF и Windows Forms. Мы работаем над исправлением этого в рамках выпуска .NET Core 3.0.
Сэмпл нативного хостинга
Недавно был опубликован Native Hosting sample. Он демонстрирует лучший подход для хостинга .NET Core в нативном приложении.
В рамках .NET Core 3.0 мы теперь предоставляем общие функциональные возможности собственным хостингам .NET Core, которые ранее были доступны только для управляемых приложений .NET Core через официально предоставляемые хостинги .NET Core. Функциональность в первую очередь связана с загрузкой сборки. Эта функциональность должна упростить создание собственных хостингов, которые могут использовать полный набор функций .NET Core.
Поддержка HTTP/2 в HttpClient
HTTP/2 является основной версией протокола HTTP. Некоторые из примечательных особенностей HTTP/2 — поддержка сжатия хедера и полностью мультиплексированные потоки по одному соединению. Хотя HTTP/2 сохраняет семантику HTTP (хедеры HTTP, методы и т.д.), он отличается от HTTP/1.x тем, как данные отправляются.
HttpClient
теперь поддерживает выполнение запросов HTTP/2. По умолчанию все также остается HTTP/1.1, но вы можете отказаться от него в пользу HTTP/2, установив версию с помощью HTTP-запроса.
var client = new HttpClient() { BaseAddress = new Uri("https://localhost:5001") };
// HTTP/1.1 request
using (var response = await client.GetAsync("/"))
{
Console.WriteLine(response.Content);
}
// HTTP/2 request
using (var request = new HttpRequestMessage(HttpMethod.Get, "/") { Version = new Version(2, 0) })
using (var response = await client.SendAsync(request))
{
Console.WriteLine(response.Content);
}
В качестве альтернативы вы можете по умолчанию отправлять запросы HTTP/2, установив DefaultRequestVersion
в HttpClient
.
var client = new HttpClient()
{
BaseAddress = new Uri("https://localhost:5001"),
DefaultRequestVersion = new Version(2, 0)
};
// Defaults to HTTP/2
using (var response = await client.GetAsync("/"))
{
Console.WriteLine(response.Content);
}
Вследствии этого изменения серверы и клиенты должны согласовать используемую версию протокола. ALPN (Application-Layer Protocol Negotiation) — это расширение TLS, которое позволяет серверу и клиенту согласовывать версию протокола, используемую в рамках их взаимодействия. Однако стоит учесть, что большинство серверов поддерживают только ALPN как единственный способ установить соединение HTTP/2. Таким образом, HTTP/2 согласовывается HttpClient
только по соединению TLS.
В сценариях разработки, когда сервер и клиент априори знают, что оба будут говорить на HTTP/2 без шифрования, вы можете установить соединение HTTP/2 через cleartext, установив переключатель AppContext
или переменную среды. (DOTNET_SYSTEM_NET_HTTP_SOCKETSHTTPHANDLER_HTTP2UNENCRYPTEDSUPPORT=1
).
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
Завершение
Мы будем очень рады, если вы попробуете новые функции. Пожалуйста, сообщайте о проблемах или багах, которые вы обнаружите. Вы также можете подавать запросы на новые функции, но их реализации придется подождать до следующего выпуска.
Сейчас мы очень близки к завершению работы над компонентом .NET Core 3.0 и теперь мы переключаем внимание команды на улучшение качества релиза. У нас впереди несколько месяцев исправления ошибок и повышения производительности.
Кстати, к следующему крупному обновлению мы переключим ветви master
в репозиториях .NET Core. Скорее всего это произойдет сразу после Preview 7 в июле.
Спасибо за то, что тестируете .NET Core 3.0. Мы ценим вашу помощь. На данный момент мы сосредоточены на том, чтобы сделать финальную версию наиболее интересной и качественной для вас.