27
20

More than 3 years have passed since last update.

.NET 6 Preview 5 の機能紹介(結構長いのでおやつでも食べながらどうぞ)

Posted at

皆さんごきげんよう。本記事は、2021 年 6 月 17 日(米国時間)ポストされた Announcing .NET 6 Preview 5 の速報的なアレというか意訳のようななにかとなります。内容については下記が原文で、正となります。すっごい長いです。


この度、満を持して .NET 6 Preview 5 をリリースいたしました。.NET 6 のリリースへの道も、ついに後半戦。重要な機能がだいぶ出そろってきましたよ!その代表例が「.NET SDK Workloads」です。これは、.NET 6 Preview 4 の紹介の際にも触れた、.NET プラットフォーム統合のビジョンの基盤となるもので、より多くのアプリケーション タイプのサポートを可能にしています。ほかの機能と同様、魅力的なエンドツーエンドのユーザー エクスペリエンスを提供するために統合されています。

.NET 6 Preview 5 (Linux 版、macOS 版、Windows 版) は以下からダウンロードいただけます。

なお、.NET 6 Preview 5 における、Web (ASP.NET) 、Data Access、クロス プラットフォームの UI シナリオに関する新機能の詳細については、ASP.NET CoreEntity Framework Core.NET MAUI それぞれ記事を用意しております。こちらを参照してください (注 : 英語です)

米国時間 2021 年 6 月 17 日、Visual Studio 2022 Preview
1
がリリースされました。.NET 6 Preview 5 もその中に含まれています。なお、.NET 6 は、Visual Studio 2019 v16.11 および Visual Studio for Mac 8.9(※) でテストされています。Visual Studio で .NET 6 を使ってみたいという方は、これらのビルド環境で試してみるのをお勧めします。

(※) uikou 注 : Visual Studio 2019 for Mac は、2021/06/21 現在、バージョン 8.10 が最新提供バージョンですが、.NET 6 の検証バージョンは 8.9 なので、ご注意ください。

なお、最新の .NET の機能についてのディスカッションの詳細は、こちらにてご覧いただけます。

.NET SDK : オプションのワークロード改善

SDK workloads は、.NET SDK の新機能です。SDK のサイズを大きくせずとも、モバイルWebAssembly などの新しいアプリケーション タイプのサポートを追加することができます。

ワークロード機能が更新され、listupdate が追加されました。こうした新機能は、最終的にどんなユーザーエクスペリエンスになるか、その感じを把握できるようになります。簡単なコマンドをいくつか実行すれば、お好みの環境を素早くセッティングすることができます。また、一旦セットした環境では、長らく最新の状態をキープすることができます。

  • dotnet workload list : インストールしたワークロードが表示されます。
  • dotnet workload update : インストールされているすべてのワークロードを利用可能な最新バージョンに更新します。

update は、更新されたワークロード マニフェストを求めて nuget.org に問い合わせをし、ローカル マニフェストを更新して、インストール済みワークロードの新バージョンをダウンロードした後、古いバージョンをすべて削除します。
この動作は、apt update および apt upgrade -y(Debian ベースの Linux ディストリビューションで使用)に似たものです。

dotnet workload コマンドは、指定の SDK のコンテキストで動作します。例えば、.NET 6 と .NET 7 の両方がインストールされているとしますと、両方を使用している場合、ワークロードが異なる(少なくとも、同じワークロードでもバージョンが異なってます)ため、workloads コマンドは異なる結果を提供してきます。こうした状況などにおいて、SDK の指定が必要になります。

このように、ワークロード昨日は、基本的に .NET SDK のパッケージ マネージャーとなります。ワークロードは、.NET 6 Preview 4 のリリースから導入されたものになります。

.NET SDK : NuGet パッケージの検証

パッケージ検証ツールでは、NuGet ライブラリの開発者が、パッケージについて、一貫性のある正しい形式であることを検証できます。

これには以下が含まれます。

  • バージョン間で重大な変更がないことを検証する。
  • パッケージが、ランタイム固有の全実装に対して、同じ Public API のセットを持つことを検証する。
  • ターゲット フレームワークやランタイムの適用性のギャップを検証する。

このツールは、Microsoft.DotNet.PackageValidation で利用いただけます。
なお、このツールに関する記事は近日公開予定です。待っててくださいね。

.NET SDK : .NET のコンパイラ プラットフォーム (Roslyn) アナライザでの分析

.NET 5 では、約 250 のアナライザを .NET SDK と併せてリリースしました。さらに、NuGet パッケージとしてもリリースされています。.NET 6 では、さらに多くのアナライザを追加しちゃいます。

既定では、新しいアナライザのほとんどは "Info" レベルで有効になっています。解析モードを次のように構成すると、これらのアナライザを "Warning" レベルで有効にすることができます。

<AnalysisMode>AllEnabledByDefault</AnalysisMode>

私たちは、.NET 6 に必要なアナライザのセット(およびいくつかの追加機能)を公開しました。それらのほとんどは入手いただけます

なお、この Preview 5 に含まれる以下の実装は、Newell Clark 氏と Meik Tranel 氏の手になるものです。
Note : 以前の Preview においても、コミュニティの皆様から他の機能について、貢献いただいております。

Contributor Issue タイトル
Newell Clark dotnet/runtime #33777 Use span-based string.Concat
Newell Clark https://github.com/dotnet/runtime/issues/33784 Prefer string.AsSpan() over string.Substring() when parsing
Newell Clark https://github.com/dotnet/runtime/issues/33789 Override Stream.ReadAsync/WriteAsync
Newell Clark https://github.com/dotnet/runtime/issues/35343 Replace Dictionary<,>.Keys.Contains with ContainsKey
Newell Clark https://github.com/dotnet/runtime/issues/45552 Use String.Equals instead of String.Compare
Meik Tranel https://github.com/dotnet/runtime/issues/47180 Use String.Contains(char) instead of String.Contains(String)

.NET SDK : プラットフォーム互換性アナライザでのカスタム ガードの有効化

CA1416 プラットフォーム互換性アナライザは、OperatingSystem.IsWindowsOperatingSystem.IsWindowsVersionAtLeast など、OperatingSystem/RuntimeInformation のメソッドを利用したプラットフォーム ガードを認識しています。

しかし、プラットフォームのチェックの結果がフィールドやプロパティにキャッシュされていたり、複雑なプラットフォームのチェック ロジックがヘルパー メソッドに定義されていたりすると、アナライザは他のガードの可能性を認識することができません。

カスタム ガードを有効にするために、新しい属性 SupportedOSPlatformGuard および UnsupportedOSPlatformGuard をカスタム ガードのメンバに対応するプラットフォーム名やバージョンをアノテーションするために追加しました。
このアノテーションは、プラットフォーム互換性アナライザのフロー分析ロジックによって認識され、重視されます。

注 : プラットフォーム互換性アナライザー(.NET 5 から)
たとえば、対象となるプラットフォーム上で、そこでサポートされていないような API や、特定のプラットフォーム固有の API を使用してしまうと、一部のプラットフォームでコードが動作しなくなってしまったりします。こうした問題で血涙を流す羽目にならないよう、開発者が誤ってプラットフォーム固有の API を使用してしまったことに気づかずリリースしてしまう前に、デザイン時にこうした問題を検出する仕組みの一つです。
.NET 5 から、プラットフォーム互換性アナライザーと、開発者がプラットフォーム固有の API を特定して適切な場所で使用できるようにするための、補完的な API が導入されています。

使い方

    [UnsupportedOSPlatformGuard("browser")] // The platform guard attribute
#if TARGET_BROWSER
    internal bool IsSupported => false;
#else
    internal bool IsSupported => true;
#endif

    [UnsupportedOSPlatform("browser")]
    void ApiNotSupportedOnBrowser() { }

    void M1()
    {
        ApiNotSupportedOnBrowser();  // Warns: This call site is reachable on all platforms.'ApiNotSupportedOnBrowser()' is unsupported on: 'browser'

        if (IsSupported)
        {
            ApiNotSupportedOnBrowser();  // Not warn
        }
    }

    [SupportedOSPlatform("Windows")]
    [SupportedOSPlatform("Linux")]
    void ApiOnlyWorkOnWindowsLinux() { }

    [SupportedOSPlatformGuard("Linux")]
    [SupportedOSPlatformGuard("Windows")]
    private readonly bool _isWindowOrLinux = OperatingSystem.IsLinux() || OperatingSystem.IsWindows();

    void M2()
    {
        ApiOnlyWorkOnWindowsLinux();  // This call site is reachable on all platforms.'ApiOnlyWorkOnWindowsLinux()' is only supported on: 'Linux', 'Windows'.

        if (_isWindowOrLinux)
        {
            ApiOnlyWorkOnWindowsLinux();  // Not warn
        }
    }
}

Windows フォーム : 既定のフォント

Application.SetDefaultFont で、アプリケーションの既定フォントを設定できるようになりました。利用可能なパターンは、使用するパターンは、高い dpi やビジュアル スタイルの設定と同様となります。

class Program
{
    [STAThread]
    static void Main()
    {
        Application.SetHighDpiMode(HighDpiMode.SystemAware);
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

+       Application.SetDefaultFont(new Font(new FontFamily("Microsoft Sans Serif"), 8f));

        Application.Run(new Form1());
    }
}

既定フォントの設定例

Microsoft Sans Serif、8pt:
vs1

Chiller、12pt :
vs2
※ このフォント見づらくない…?

.NET Core 3.0 にて、既定フォントが更新されました。しかし、この変更は、アプリケーションを .NET Framework から .NET Core に移行しようと考える一部のユーザーにとって、移行についての大きなハードルとなっていました。今回の変更により、アプリケーションに必要なフォントを簡単に選択できるようになりましたので、移行のハードルが取り払われることになりました。やったね。

ライブラリ : 古いフレームワークのサポート終了

パッケージからフレームワークを削除することは、かなり重大な変更となります。その一方で、これまでに出荷したすべてのフレームワークすべてをターゲットしてビルドし続けることは、パッケージの複雑性とサイズの増加につながります。これまで、私たちはこの問題を収集 (harvesting) という方法で解決してきました。

  1. 現在のフレームワーク用にのみビルドする
  2. ビルド時に、以前のバージョンのパッケージをダウンロードして、ビルド対象外の以前のフレームワークのバイナリを収集する。

こうしたことは、フレームワークの削除の心配なしに、いつでもアップデートできるということである一方、収集されたバイナリを使用した場合、バグフィックスや新機能を取得できないということでもあります。つまり、収集されたアセットは、今現在で hidden 状態となっているサービスを受けられません。これは、あなたの視点では、私たちがもはやアップデートしていない古いバイナリを利用しているにもかかわらず、パッケージをアップデートし続けることができてしまうことになるためです。

.NET 6 Preview 5 からは、リリースするすべてのアセットがサービスを受けられるようにするため、いかなる形式の収集も行わない予定です。これは、以下のバージョンより古いフレームワークのサポートを終了することを意味します。

  • .NET Framework 4.6.1
  • .NET Core 3.1
  • .NET Standard 2.0

以前のフレームワークの影響を受けるパッケージをあなたが参照している場合、参照パッケージを今後のバージョンに更新することはできなくなります。対応の選択肢は、プロジェクトを今後のフレームワークのバージョンに再度ターゲットするか、参照パッケージを更新しないかのいずれかになります(いずれにしても、すでにフリーズされたバイナリを利用しているため、一般的にはそれほど大きな問題ではありません)。

影響を受けるパッケージの全リストを含む詳細については、下記をご覧ください。

ライブラリ:Microsoft.Extensions

本リリースでは、Microsoft.Extensions の API を改善してきました。Preview 5 では、ホスティングと依存関係の挿入にフォーカスしました。(なお、Preview 4 では、ロギングのためのコンパイル時ソース生成機能を追加しています)

※ Credit to Martin Björkströmdotnet/runtime #51840 (AsyncServiceScope).

ホスティング : ConfigureHostOptions API

IHostBuilder に新しい ConfigureHostOptions API を追加しました。アプリケーションのセットアップがより簡単になりました(例:シャットダウンのタイムアウトの設定)。

using HostBuilder host = new()
    .ConfigureHostOptions(o =>
    {
        o.ShutdownTimeout = TimeSpan.FromMinutes(10);
    })
    .Build();

host.Run();

Preview 5 以前は、ホスト オプションの設定がちょいとばかり雑でした…。

依存関係の挿入 : CreateAsyncScope API

IAsyncDisposable サービスを登録すると、サービス プロバイダwを廃棄すると、InvalidOperationException がスローされることにお気づきになる方もいるかもしれません。

新しい CreateAsyncScope API は、以下のように、簡単な解決策を提供します。

await using (var scope = provider.CreateAsyncScope())
{
    var foo = scope.ServiceProvider.GetRequiredService<Foo>();
}

また、以下の例では、既存の問題と、先に提案したワークアラウンドとなります。

using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;

await using var provider = new ServiceCollection()
        .AddScoped<Foo>()
        .BuildServiceProvider();

// This using can throw InvalidOperationException
using (var scope = provider.CreateScope())
{
    var foo = scope.ServiceProvider.GetRequiredService<Foo>();
}

class Foo : IAsyncDisposable
{
    public ValueTask DisposeAsync() => default;
}

返されたスコープを IAsyncDisposable にキャストすることで、この例外を回避できます。

var scope = provider.CreateScope();
var foo = scope.ServiceProvider.GetRequiredService<Foo>();
await ((IAsyncDisposable)scope).DisposeAsync();

CreateAsyncScope はこの問題を解決し、using ステートメントを安全に使用できるようにしてくれます。

ライブラリ : JsonSerializer ソースの生成

ほぼすべての .NET シリアライザのバックボーンはリフレクションです。

リフレクションは特定のシナリオでは優れた能力を発揮しますが、(通常から、多くの JSON ドキュメントをシリアル化 / 逆シリアル化して処理しているような)高性能なクラウド ネイティブ アプリケーションの基盤には適していません。リフレクションは、[起動時]、メモリ使用量、およびアセンブリのトリミングに問題がでてきます。

ランタイムのリフレクションの代わりになるのが、コンパイル時のソース生成です。ソース ジェネレータは、ライブラリやアプリケーション ビルドの一部として、コンパイル可能な C# ソース ファイルを生成してくれます。
コンパイル時にソースコードを生成することで、パフォーマンスの向上など、.NET アプリケーションに多くのメリットをもたらしてくれます。

.NET 6 では、System.Text.Json.JSON の一部として新しいソース ジェネレータが含まれています。この JSON ソース ジェネレータは、JsonSerializer と連携して動作し、複数の方法で構成することができます。この新しいソース ジェネレータを使用するかどうかはあなた次第ですが、利用した場合は以下のようなメリットが得られるかと思います。

  • 起動時間の短縮
  • シリアル化処理のスループット向上
  • プライベート メモリ使用量の削減
  • System.Reflection および System.Reflection.Emit のランタイム使用の削除
  • トリムと互換性のある JSON シリアル化を可能にする

たとえば、Reflection.Emit を使って、(プライベートメモリを使用し、起動コストがかかる)逆シリアル化中にクラスのプロパティを取得・設定するためのメソッドをランタイムに動的に生成する代わりに、ソースジェネレータは、よりシンプル、かつ効率的にプロパティに直接値を割り当てたり、プロパティから値を取得したりするコードを生成することができます。しかもこいつがなかなかに高速に実行できるのです。

ソースジェネレータを試すには、System.Text.Json NuGet パッケージの最新プレビュー版を利用してみてください。私たち開発チームは、SDK にソース ジェネレータを含めるためのプロポーザルを進めています。

最適化されたシリアル化ロジックの生成

既定では、JSON ソース ジェネレータは、指定されたシリアル化可能な型のシリアライズ ロジックを生成してくれます。これにより、Utf8JsonWriter を直接使用するソースコードを生成することで、既存の JsonSerializer メソッドを使用するよりも高いパフォーマンスを実現できます。
とどのつまり、ソース ジェネレータは、実行時のエクスペリエンスを向上させるために、コンパイル時に異なる実装を与える方法を提供してくれるのです。

JsonSerializer は、JSON フォーマットから、逆に JSON フォーマットへ、.NET 型タイプのシリアル化、逆シリアル化を改善するための多くの機能(そしてさらに多くの機能が登場していますよ…!)を備えた強力なツールです。
ただ、JsonSerializer は高速ですが、シリアル化ルーチンに必要な機能のサブセットのみを使用する場合、パフォーマンスのオーバーヘッドが発生する可能性があります。今後は、JsonSerializer と新しいソースジェネレータを一緒に更新していく所存です。

  • シンプルなタイプの例
namespace Test
{
    internal class JsonMessage
    {
        public string Message { get; set; }
    }
}

JsonSerializerOptionsAttribute を介して、最高のシリアル化スループットを提供するソース生成モードでサポートされる JsonSerializer 機能のセットを定義しました。

これらの機能は、実行時余分なチェックを避けるために、前もってソース ジェネレータに指定することができます。属性が使用されない場合は、実行時に既定の JsonSerializationOptions が想定されることになります。

ビルド処理の一部として、ソース ジェネレータは JsonContext 部分クラスを次のような形で拡張します。

internal partial class JsonContext : JsonSerializerContext
{
    public static JsonContext Default { get; }

    public JsonTypeInfo<JsonMessage> JsonMessage { get; }

    public JsonContext(JsonSerializerOptions options) { }

    public override JsonTypeInfo GetTypeInfo(Type type) => ...;
}

このモードでのシリアライザの呼び出し例です。可能な限り最高のパフォーマンスが得られます。

using MemoryStream ms = new();
using Utf8JsonWriter writer = new(ms);

JsonContext.Default.JsonMessage.Serialize(writer, new JsonMessage { "Hello, world!" });
writer.Flush();

// Writer contains:
// {"Message":"Hello, world!"}

あるいは、引き続き JsonSerializer を使い、代わりに生成されたコードのインスタンスを JsonContext.Default.JsonMessage で渡すこともできます。

JsonContext.Default.JsonMessage.JsonSerializer.Serialize(jsonMessage, JsonContext.Default.JsonMessage);

似たようなやりかたですが、オーバーロードが異なるものも紹介しますね。

JsonSerializer.Serialize(jsonMessage, typeof(JsonMessage), JsonContext.Default);

これらの 2 つのオーバーロードの違いですが、1 つ目は型付きのメタデータ実装である JsonTypeInfo<T> を使用していること、2 つ目は、より一般的な型付けされていない実装を使っており、型付きの実装がコンテキスト インスタンス内に存在するかどうかを判断するために型テストを行います。

結果的には(型付けテストのために)少し動作が遅くなります。与えられた型に対してソースで生成された実装がない場合、シリアライザは NotSupportedException をスローします。リフレクション ベースの実装にフォールバックすることはありません(これは、設計上の明示的な選択です)。

Utf8JsonWriter をベースにした、最速かつ最適化されたソース生成モードは、現在のところシリアル化にのみ利用可能です。Utf8JsonReader をベースにした逆シリアル化のサポートは、皆様からのフィードバックに応じて将来提供されるかもしれません。

しかし、ソース ジェネレータは、逆シリアル化にも役立つ型のメタデータの初期化ロジックも発行します。事前に生成されたタイプメタデータを使用して JsonMessage のインスタンスを逆シリアル化するには、次のようにします。

JsonSerializer.Deserialize(json, JsonContext.Default.JsonMessage);

上記のシリアル化と同様、以下のように書くこともできます。

JsonSerializer.Deserialize(json, typeof(JsonMessage), JsonContext.Default);

その他の注意事項

  • 派生した部分的な JsonSerializerContext インスタンスの [JsonSerializable] を介して、複数の型をソース生成に含めることができます。
  • また、ソース ジェネレータは、プリミティブ型だけでなく、オブジェクト上のネストされたオブジェクトおよびコレクション メンバーもサポートします。

ライブラリ : WebSocket の圧縮

ネットワークを介して送信されるデータには圧縮が重要です。WebSocket では圧縮が可能になりました。私たちは、RFC 7692 の WebSockets 用の permessage-deflate extension の実装を使用しました。これは、DEFLATE アルゴリズムを使用して WebSockets メッセージのペイロードを圧縮する機能です。

この機能は、GitHub の Networking に対するユーザーからの要望の中でもトップレベルのものでした。このAPIを提供するまでの道のりは、API review 1API review 2 で見ることができます。

Ivan Zlatanov 氏の功績です。サンキュー Ivan!

ところで、ここで何なんですが、私たちは、圧縮と暗号化を同時に使用すると、CRIME や BREACH のような攻撃を受ける可能性があることに気づいてしまいました。

つまり、Secret をユーザーが生成したデータと一緒に 1 つの圧縮コンテキストで送信することはできないということです。そうしないと Secret が抜かれちゃう可能性があります。こういう事の影響を、ユーザーに知ってもらい、リスクについて判断してもらえるようにするために、API の名前を DangerousDeflateOptions に変更しました。また、特定のメッセージの圧縮をオフにする機能も追加しました。これにより、ユーザーが Secret を送信したい場合、圧縮なしで安全に送信することができるようになります。

またもやIvan 氏の神フォローアップにより、圧縮を無効にした場合の WebSocket のメモリ フットプリントが約 27 %も削減されました。やったね。

クライアント側で圧縮を有効にするのは簡単です。ぜひ、以下の例を参考にしてみててくださいね。
ただし、サーバーは設定をネゴシエートすることができます。例えば、より小さい (TCP) ウィンドウを要求したり、圧縮を完全に拒否することができますので、ご注意ください。

※ 注 : ウィンドウって何?というあたりはこちらなど

var cws = new ClientWebSocket();
cws.Options.DangerousDeflateOptions = new WebSocketDeflateOptions()
{
    ClientMaxWindowBits = 10,
    ServerMaxWindowBits = 10
};

ASP.NET Core の WebSocket 圧縮サポートも最近追加されました。これは今後のプレビューに含まれていく予定です。

ライブラリ : Socks プロキシのサポート
SOCKS は、あらゆる TCP/UDP トラフィックを処理できるプロキシ サーバーの実装であり、非常に汎用性の高いシステムです。これは長年コミュニティから頂いていた要望でしたが、満を持して .NET 6 に追加されました。やったね。

本リリースでの変更により、Socks4、Socks4a、Socks5 のサポートが追加されました。例えば、SSH による外部接続のテストや、Tor ネットワークへの接続などが可能になったのです。やったね。

そんなわけで、以下の例のように WebProxy クラスが Socks スキーマを受け付けるようになりました。

var handler = new HttpClientHandler
{
    Proxy = new WebProxy("socks5://127.0.0.1", 9050)
};
var httpClient = new HttpClient(handler);

Huo さん、ありがとうございました!

ライブラリ : OpenTelemetry メトリックのサポート

私たちは、可観測性(※)にフォーカスした取り組みの一環として、過去数回の .NET のリリースにおいて OpenTelemetry のサポート追加してきました。

(※) 可観測性

.NET 6 では、OpenTelemetry Metrics API のサポートを追加します。OpenTelemetry のサポートを追加することで、アプリケーションは他の OpenTelemetry システムとシームレスに相互運用できるようになります。

System.Diagnostics.Metrics は、OpenTelemetry Metrics API 仕様の .NET 実装になります。Metrics API は、何も手を加えていない状態の、そのままの測定値を処理するために明示的に設計されています。通常は、継続的な測定値のサマリを効率的かつ同時に生成することを目的としたものになります。

API には、計測につかうオブジェクト(Counterなど)の作成に使用できる Meter クラスが含まれています。API では計測するためのクラスとして、CounterHistogramObservableCounterObservableGauge の 4 つのクラスを公開しており、さまざまな基準となるシナリオをサポートしています。また、API では MeterListener クラスが公開されており、集計やグループ化のために記録された測定値をリッスンすることができます。

OpenTelemetry .NET の実装は、これらの新しい API を使用するように拡張されており、メトリックの観測シナリオのサポートが追加されます。

観測・記録の例

    Meter meter = new Meter("io.opentelemetry.contrib.mongodb", "v1.0");
    Counter<int> counter = meter.CreateCounter<int>("Requests");
    counter.Add(1);
    counter.Add(1, KeyValuePair.Create<string, object>("request", "read"));

リスニングの例

    MeterListener listener = new MeterListener();
    listener.InstrumentPublished = (instrument, meterListener) =>
    {
        if (instrument.Name == "Requests" && instrument.Meter.Name == "io.opentelemetry.contrib.mongodb")
        {
            meterListener.EnableMeasurementEvents(instrument, null);
        }
    };
    listener.SetMeasurementEventCallback<int>((instrument, measurement, tags, state) =>
    {
        Console.WriteLine($"Instrument: {instrument.Name} has recorded the measurement {measurement}");
    });
    listener.Start();

ライブラリ : BigInteger のパフォーマンス

10 進数および 16 進数の文字列からの BigIntegers の解析が改善されました。以下のグラフのように、最大で 89% の改善が見られます。

vs3

Joseph さん、ありがとうございます。ありがとうございます。

ライブラリ : Vector の nint および nuint をサポート

Vector<T> が C#9 で追加された nint と nuint のプリミティブ型をサポートするようになりました。この変更によって、例えばポインタやプラットフォーム依存の長さの SIMD 命令をより簡単に使用することができるようになりました。

ライブラリ : OpenSSL 3 サポート

.NET の暗号化 API は、Linux 上で推奨されるネイティブな暗号化プロバイダとして OpenSSL 3 の使用をサポートします。.NET 6 では、OpenSSL 3 が利用可能な場合は OpenSSL 3 を、利用できない場合は、OpenSSL 1.x を使用します。

ライブラリ : ChaCha20/Poly1305 暗号アルゴリズムのサポートを追加

System.Security.CryptographyChaCha20Poly1305 クラスが追加されました。ChaCha20/Poly1305 アルゴリズムを使用するには、ベースとなる OS でサポートされている必要があります。static IsSupported プロパティを使用して、特定のコンテキストでアルゴリズムがサポートされているかどうかを判断できます。

  • Linux:OpenSSL 1.1 以上
  • Windows:ビルド 20142 以上(日本時間の 2021 年 6 月 21 日現在、Developer Insider Channel が必要です。(以下リンク日本語)

  • Linux

  • Windows

Linux については、Kevin さんのサポートのおかげです。ありがとうございました!

Interop : Objective-C 相互運用のサポート

.NET のための単一の Objective-C 相互運用の実装を目標として、Objective-C サポートを追加しました。

これまで、Objective-C の相互運用システムは Mono embedding API を中心に構築されていましたが、ランタイム間で共有するには適切なアプローチではないという判断になりました。結果として、新たに .NET API を作成し、最終的には両ランタイムで動作する単一の Objective-C 相互運用エクスペリエンスを可能にすることになりました。

この Objective-C 相互運用のための新 API により、両ランタイムで、NSAutoreleasePool がすぐにサポートされるようになりました。NSAutoreleasePoolは、Cocoa の参照カウント方式のメモリ管理システムのサポートを可能にします。各管理対象スレッド に暗黙の NSAutoreleasePool を持たせるかどうかを設定できるようになりました。これにより、スレッドごとに Cocoa オブジェクトのリリースが可能になります。

診断機能(EventPipe/DiagnosticsServer) - MonoVM

.NET 6 以降、MonoVM には数多くの診断機能が追加されている。これにより、マネージドなEventSource / EventListener、EventPipe、DiagnosticsServerといった機能が実現されている。また,デスクトップだけでなくモバイル デバイス(iOS / Android) 上で動作するアプリケーションに対しても,dotnet-tracedotnet-countersdotnet-stacks といった診断ツールを使用できるようになりました。

これらの新機能により,PrefView/SpeedScope/Chromium,dotnet-trace などのツールでMonoVMが生成したnettraceファイルを解析したり、TraceEvent などのライブラリを使ってカスタム パーサーを記述したりすることが可能になりました。

そんなわけで、今後主に SDK の統合と、より多くのネイティブ ランタイム イベント (Microsoft-Windows-DotNETRuntime) を MonoVM に適応させ、nettrace ファイルでより多くのイベントを有効にしていくことなど、機能を追加していく予定です。

現時点では、以下のような機能が実装されています。

  • DiagnosticsServer に TCP/IP サポートを追加し、その設定を利用してMonoVM iOS/Android ランタイム パックを構築する。(モバイルプラットフォームをサポートするために必要)
  • BCL EventSources は MonoVM 上で動作し、EventPipe にイベントを発行します。
  • System.Diagnostics.Tracing.RuntimeEventSource が発する BCL ランタイム カウンタは、MonoVM に接続され、dotnet-counters のようなツールから利用できます。
  • カスタム イベントソースは MonoVM 上で実行されます。カスタム イベントを EventPipe に発行し、dotnet-trace のようなツールから利用できます。
  • カスタム イベント カウンタは、MonoVM 上で動作し、カスタム カウンター イベントを EventPipe に発行し、dotnet-counters のようなツールから利用できます。
  • サンプル プロファイラは MonoVM 上に実装され、EventPipe にイベントを発行します。これにより、MonoVM 上で dotnet-trace を使った CPU プロファイリングが可能になります

  • dotnet-dsrouter 診断ツールの実装により、dotnet-tracedotnet-countersdotnet-stack など既存の診断ツールを、モバイル ターゲット上で動作する MonoVM とともに、既存のツールを変更することなく使用できるようになります。dotnet-dsrouter は、診断ツールからのすべてのトラフィックを、シミュレータ、あるいはデバイス上の MonoVM で動作する DiagnosticsServer にルーティングするローカル プロセス間通信(IPC)サーバを実行します。
  • コンポーネント ベースのアーキテクチャを用いた MonoVM での EventPipe/DiagnosticsServer の実装。

iOS における CPU サンプリング (SpeedScope)

以下は、iOS の起動時の CPU サンプリング セッションの一部を SpeedScope で表示したものです。

cpu

Android における CPU サンプリング(PerfView)

以下は、Android の CPU サンプリングを PerfView で表示したものです。(メインスレッドが無期限で Sleep 状態にされています)

CPU2

ランタイム : CodeGen

RyuJIT では、以下の変更が行われました。

Community の貢献

  • 使われていないダミー BB 変数の削除

  • ビッグ エンディアン形式の整数を読み取る未使用の関数の削除

  • 新しいスコープを作成する代わりに TYP_FLOAT を gtNewDconNode に渡す

これらの貢献をしてくださった @SingleAccretion 各位に感謝をささげます。

Dynamic PGO https://github.com/dotnet/runtime/issues/43618

  • インライン スケール計算の修正

  • optReachable に除外ブロックのチェックを追加

  • 空のフローの最適化に関するブランチを一般化

  • 新しい GetLikelyClass PGO レコード タイプのための MCS jitflags サポートの追加

  • crossgen2 の決定論サポートのための、末尾呼び出しの後の有効な IR チェックを一般化

  • より一般的な value class の準仮想化

  • 連鎖ガード付き準仮想化

pic

JITループの最適化 https://github.com/dotnet/runtime/issues/43549

  • 改善されたループ反転は、 BenchE で優れたパフォーマンスの改善を示しています。

im

  • 複製されたループ ブロックの重みをスケーリングする

  • エッジ上の既存のプロファイル データ保持のために、ループ クローニング中に preds リストを再計算しない

  • DOTフローグラフ ダンプの改善

  • ループ展開ドキュメントの改善

LSRA https://github.com/dotnet/runtime/issues/43318

Allocating Registers テーブルにレジスタ選択のヒューリスティックを含める

※ 新旧テーブル比較

teb

構造体のレジスタ内保持 https://github.com/dotnet/runtime/issues/43867

  • レジスタ内の構造体用 JIT バックエンドの準備

  • Liveness fix for struct enreg

  • 構造体の初期化の改善 ASG struct(LCL_VAR, 0) を STORE_LCL_VAR struct(0) として保持するための構造体の初期化の改善

最適化とデバッグのエクスペリエンス

  • nint / nuint 用 Vector64 / 128 / 256 を認識して処理する

  • よりデバッグエクスペリエンスを向上させるための clrjit.natvis ファイルの追加

  • jitstd::list のサンプル ビジュアライザと同様、RefPosition とその中の registerAssignment の分解で全レジスタを表示 :

pro

SIMD

SIMD や HWIntrinsics を含む特定のメソッドをインライン化することで、コード生成とパフォーマンスが向上しました。(最大で 95% の改善)

SIMD

まとめ

.NET 6 Preview 5 は、機能の幅広さだけでなく、量においても、おそらくこれまでの最大のプレビューになります。Roslyn の機能が、ソース ジェネレータやアナライザなどの低レベルのライブラリの機能にどれだけ影響を与えているかがお分かりいただけるのではないでしょうか。
まさに未来が到来したのです。現在、かなり高レベルで最適化された正しいコードを生成することができて、ご自身のプロジェクトで全く同じエクスペリエンスを実現することができる、非常に有能なコンパイラ ツールチェーンができたのです。

まさに今、.NET 6 をテストの絶好のチャンスです。2021 年 11 月まで、リリースまでお待ちいただく必要がありますが、現在から 3 か月以上もの間、出荷までの時間があるということは、フィードバックの窓口が近いうちに深刻度が高い問題のみに徐々に絞られていくことは想像に難くありません。
チームは約 1.5 リリース回の分程度、先のプレビューを先取りして作業していますが、近々、クオリティに主なフォーカスが移っていくようになると考えています。ぜひ、あなたも .NET 6 を試してみてください。

Thanks for being a .NET developer!


以上、リチャードさんでした。

re

それではみなさんごきげんよう。長かった。

27
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
20