Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym artykule opisano nowe funkcje w środowisku uruchomieniowym .NET dla .NET 11. Ostatnia aktualizacja dotyczyła wersji zapoznawczej 3.
Zaktualizowano minimalne wymagania sprzętowe
Minimalne wymagania sprzętowe dla .NET 11 zostały zaktualizowane, aby wymagać bardziej nowoczesnych zestawów instrukcji dla architektur x86/x64 i Arm64. Ponadto cele kompilacji ReadyToRun (R2R) zostały zaktualizowane, aby korzystać z nowszych możliwości sprzętowych.
Wymagania dotyczące arm64
W przypadku firmy Apple nie ma żadnych zmian w minimalnych wymaganiach sprzętowych ani w celu ReadyToRun. Mikroukłady Apple M1 są w przybliżeniu równoważne armv8.5-a i zapewniają obsługę co najmniej zestawów instrukcji takich jak AdvSimd (NEON), CRC, DOTPROD, LSE, RCPC, RCPC2, i RDMA.
W przypadku systemu Linux nie ma żadnych zmian w minimalnym sprzęcie. .NET nadal obsługuje urządzenia, takie jak Raspberry Pi, które mogą zapewnić obsługę zestawu instrukcji AdvSimd. Element docelowy ReadyToRun został zaktualizowany, aby obsługiwać zestaw instrukcji LSE, co może spowodować dodatkowe obciążenie związane z kompilacją JIT po uruchomieniu aplikacji.
W przypadku Windows punkt odniesienia jest aktualizowany w celu wymagania zestawu instrukcji LSE. Jest to wymagane przez Windows 11 i przez wszystkie procesory Arm64 oficjalnie obsługiwane przez Windows 10. Ponadto jest zgodny z wymaganiami Arm SBSA (Server Base System Architecture). Element docelowy ReadyToRun został zaktualizowany na armv8.2-a + RCPC, który zapewnia obsługę co najmniej AdvSimd, CRC, LSE, RCPC i RDMA, oraz obejmuje większość oficjalnie obsługiwanego sprzętu.
| System operacyjny | Poprzednie minimum JIT/AOT | Nowe minimum trybu JIT/AOT | Poprzedni cel R2R | Nowy cel R2R |
|---|---|---|---|---|
| Jabłko | Apple M1 | (Brak zmian) | Apple M1 | (Brak zmian) |
| Linux | armv8.0-a | (Brak zmian) | armv8.0-a | armv8.0-a + LSE |
| Windows | armv8.0-a | armv8.0-a + LSE | armv8.0-a | armv8.2-a + RCPC |
Wymagania dotyczące x86/x64
W przypadku wszystkich trzech systemów operacyjnych (Apple, Linux i Windows) punkt odniesienia jest aktualizowany z x86-64-v1 do x86-64-v2. Spowoduje to, że sprzęt, który gwarantował tylko CMOV, CX8, SSE i SSE2, teraz dodatkowo będzie gwarantował również CX16, POPCNT, SSE3, SSSE3, SSE4.1 i SSE4.2. Ta gwarancja jest wymagana przez Windows 11 i przez wszystkie procesory x86/x64 oficjalnie obsługiwane w Windows 10. Obejmuje wszystkie układy nadal oficjalnie wspierane przez Intel i AMD, z ostatnimi starszymi układami, które wyszły z wsparcia około 2013 roku.
Element docelowy ReadyToRun został zaktualizowany do x86-64-v3 dla Windows i Linux, co dodatkowo obejmuje zestawy instrukcji AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT i MOVBE. Cel ReadyToRun dla Firmy Apple pozostaje niezmieniony.
| System operacyjny | Poprzednie minimum JIT/AOT | Nowe minimum trybu JIT/AOT | Poprzedni cel R2R | Nowy cel R2R |
|---|---|---|---|---|
| Jabłko | x86-64-v1 | x86-64-v2 | x86-64-v2 | (Brak zmian) |
| Linux | x86-64-v1 | x86-64-v2 | x86-64-v2 | x86-64-v3 |
| Windows | x86-64-v1 | x86-64-v2 | x86-64-v2 | x86-64-v3 |
Wpływ
Począwszy od .NET 11, .NET nie można uruchomić na starszym sprzęcie i może wyświetlić komunikat podobny do następującego:
Obecnemu procesorowi CPU brakuje jednego lub więcej bazowych zestawów instrukcji.
W przypadku zestawów z obsługą funkcji ReadyToRun może istnieć dodatkowe obciążenie związane z uruchamianiem na niektórych obsługiwanych sprzętach, które nie spełniają oczekiwanej obsługi typowego urządzenia.
Przyczyna zmiany
.NET obsługuje szeroką gamę sprzętu, często powyżej i poza minimalnymi wymaganiami sprzętowymi wprowadzonymi przez bazowy system operacyjny. Ta obsługa zwiększa znaczącą złożoność bazy kodu, szczególnie w przypadku znacznie starszego sprzętu, który jest mało prawdopodobne, aby nadal był używany. Ponadto definiuje "najniższy wspólny mianownik", który musi być domyślnym poziomem dla celów AOT, co może w niektórych scenariuszach prowadzić do zmniejszenia wydajności.
Wprowadzono aktualizację do minimalnej linii bazowej w celu zmniejszenia złożoności konserwacji bazy kodu i lepszego dopasowania do udokumentowanych (i często wymuszanych) wymagań sprzętowych bazowego systemu operacyjnego.
Aby uzyskać więcej informacji, zobacz Minimalne wymagania sprzętowe zaktualizowane.
Asynchronizuj środowisko uruchomieniowe
.NET 11 wprowadza natywną obsługę asynchroniczności w środowisku uruchomieniowym (Runtime Async V2), co stanowi znaczący krok w kierunku zastąpienia maszyn stanu asynchronicznych generowanych przez kompilator poprzez zawieszenie i wznowienie zarządzane przez środowisko uruchomieniowe. Zamiast generowania klas maszyn stanów przez kompilator, to środowisko uruchomieniowe śledzi wykonywanie asynchroniczne, co prowadzi do tworzenia czystszych śladów stosu, lepszego debugowania i niższego obciążenia.
Runtime Async to funkcja w wersji przeglądowej. Aby wyrazić zgodę, dodaj następującą właściwość do pliku projektu:
<PropertyGroup>
<Features>runtime-async=on</Features>
</PropertyGroup>
Począwszy od wersji zapoznawczej 3, net11.0 projekt nie wymaga <EnablePreviewFeatures>true</EnablePreviewFeatures> już używania asynchronicznego środowiska uruchomieniowego.
Czystsze ślady stosu w czasie rzeczywistym
Najbardziej widoczne ulepszenia to ślady stosu na żywo — jakie profileery, debugery i new StackTrace() zobaczą podczas wykonywania. Dzięki asynchroniczności generowanej przez kompilator, każda metoda asynchroniczna tworzy wiele ramek z infrastruktury maszyny stanowej. Za pomocą asynchronicznego środowiska uruchomieniowego rzeczywiste metody są wyświetlane bezpośrednio na stosie wywołań.
// To enable runtime async, add the following to your .csproj:
// <Features>runtime-async=on</Features>
await OuterAsync();
static async Task OuterAsync()
{
await Task.CompletedTask;
await MiddleAsync();
}
static async Task MiddleAsync()
{
await Task.CompletedTask;
await InnerAsync();
}
static async Task InnerAsync()
{
await Task.CompletedTask;
Console.WriteLine(new StackTrace(fNeedFileInfo: true));
}
Bez runtime-async— 13 ramek, widoczna infrastruktura stanu maszyny:
at Program.<<Main>$>g__InnerAsync|0_2() in Program.cs:line 24
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](...)
at Program.<<Main>$>g__InnerAsync|0_2()
at Program.<<Main>$>g__MiddleAsync|0_1() in Program.cs:line 14
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](...)
at Program.<<Main>$>g__MiddleAsync|0_1()
at Program.<<Main>$>g__OuterAsync|0_0() in Program.cs:line 8
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](...)
at Program.<<Main>$>g__OuterAsync|0_0()
at Program.<Main>$(String[] args) in Program.cs:line 3
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](...)
at Program.<Main>$(String[] args)
at Program.<Main>(String[] args)
Z runtime-async—5 ramkami prawdziwy łańcuch wywołań:
at Program.<<Main>$>g__InnerAsync|0_2() in Program.cs:line 24
at Program.<<Main>$>g__MiddleAsync|0_1() in Program.cs:line 14
at Program.<<Main>$>g__OuterAsync|0_0() in Program.cs:line 8
at Program.<Main>$(String[] args) in Program.cs:line 3
at Program.<Main>(String[] args)
Uwaga / Notatka
Ślady stosu wyjątków (z catch (Exception ex)) wyglądają już tak samo, niezależnie od tego, czy jest używany środowisko uruchomieniowe Async, czy nie, ponieważ istniejące ExceptionDispatchInfo czyszczenie w kodzie generowanym przez kompilator obsługuje ten przypadek. Ulepszenia są widoczne podczas wykonywania na żywo.
To ulepszenie przynosi korzyści wszystkim, co sprawdza stos wykonywania na żywo, w tym narzędzia profilowania, rejestrowanie diagnostyczne i okno stosu wywołań debugera.
Wsparcie dla NativeAOT i ReadyToRun
Wersja zapoznawcza 3 dodaje obsługę asynchronicznego środowiska uruchomieniowego dla kompilacji NativeAOT i ReadyToRun. Rozszerza to funkcję poza skompilowany kod JIT do scenariuszy skompilowanych przed czasem. Środowisko uruchomieniowe ponownie używa obiektów kontynuacji bardziej agresywnie i pozwala uniknąć zapisywania niezmienionych lokalnych zmiennych, zmniejszając ciśnienie alokacji w kodzie o dużej liczbie operacji asynchronicznych.
Ulepszenia debugowania
Punkty przerwania są teraz poprawnie powiązane wewnątrz metod asynchronicznych środowiska uruchomieniowego, a debuger może przechodzić przez await granice bez przechodzenia do infrastruktury generowanej przez kompilator.
Ulepszenia kompilacji JIT
-
Eliminacja sprawdzania granic: Kompilator just in time (JIT) eliminuje teraz kontrole granic dla wspólnego wzorca, w którym indeks plus stała jest porównywana z długością, taką jak
i + cns < len. Eliminuje również dodatkowe sprawdzanie granic dla dostępu z użyciem indeksacji od końca (na przykładvalues[^1]). Te ulepszenia zmniejszają nadmiarowe kontrole w ciasnych pętlach i zwiększają przepływność operacji tablicy i zakresu. - Usuwanie nadmiarowego kontekstu sprawdzonego: JIT może teraz udowodnić i usunąć nadmiarowe konteksty sprawdzone arytmetycznie — na przykład kiedy wartość jest już znana jako mieszcząca się w zakresie. Ta optymalizacja eliminuje niepotrzebne kontrole przepełnienia wygenerowanego kodu.
-
Składanie wyrażeń przełącznika: Wyrażenia wieloetapowe
switchteraz redukują się do prostszych, bezrozgałęzionych sprawdzeń, gdy elementy docelowe stanowią mały zbiór stałych, na przykładx is 0 or 1 or 2 or 3 or 4. -
Szybsze rzutowania uint do float/double: Rzutowanie
uintdofloatlubdoublejest szybsze na sprzęcie x86 sprzed AVX-512. - Devirtualizacja w obrazach ReadyToRun: Obrazy ReadyToRun (R2R) mogą teraz dewiirtualizować wywołania ogólnych metod wirtualnych, które nie są współdzielone, zwiększając wydajność kodu skomplikowanego z wyprzedzeniem dla scenariuszy ogólnych.
-
Funkcje wewnętrzne SVE2: Nowe funkcje wewnętrzne SVE2 (skalowalne rozszerzenie wektora 2) są dostępne:
ShiftRightLogicalNarrowingSaturate(Even|Odd). Rozszerzają one zestaw operacji wektoryzowanych dostępnych na sprzęcie arm obsługującym protokół SVE2.
Ulepszenia maszyny wirtualnej
- Wysyłanie buforowanego interfejsu na platformach innych niż JIT: Na platformach, które nie obsługują trybu JIT, takich jak iOS, wysyłanie interfejsu wracało do kosztownej ogólnej ścieżki naprawy. Buforowana wysyłka daje do 200-krotne ulepszenia kodu o dużym obciążeniu interfejsem w tych miejscach docelowych.
-
Guid.NewGuid()w systemie Linux:Guid.NewGuid() na Linuksie teraz używa się syscall z buforowaniem wsadowym zamiast odczytu zgetrandom(), co daje około 12% poprawy wydajności dla generowania identyfikatorów GUID.
Ulepszenia zestawu WebAssembly
Wersja zapoznawcza 3 rozszerza obsługę przeglądarki i zestawu WebAssembly z kilkoma ulepszeniami:
- Ładowanie ładunku webCIL: Środowisko uruchomieniowe może teraz ładować ładunki webCIL bezpośrednio, poprawiając zgodność ze scenariuszami wdrażania opartymi na przeglądarce.
- Ulepszone symbole debugowania: Jakość symboli i śledzenia stosu do debugowania WebAssembly została ulepszona, co ułatwia diagnostykę problemów w aplikacjach .NET hostowanych w przeglądarce.
-
float[],Span<float>iArraySegment<float>marshaling:float[],Span<float>, iArraySegment<float>są teraz marshaling bardziej bezpośrednio przez granice języka JavaScript, co zmniejsza obciążenie dla międzyoperacyjnego kodu.