【.NET 10.0】 dnx 【Preview 6】
.NET 10.0 Preview 6 が昨日寝る前にリリースされていました。いくつか気になった点を摘んでみます。
dnx
& dotnet tool exec
npx
(Node.js Package eXecute?) と同じようにパッケージのインストールなしで dotnet tool を実行できるようになりました。
dnx PackageName --yes -- [options...]
--yes
付けないと初回実行時に実行して良いか聞かれる仕様、npx
と同じなんだけど要るかなコレ? CI/CD 向けにインストールなしで実行って用途なんでは。。。
今のところ NuGet パッケージの ToolCommandName
からパッケージ名を引いてくるという処理は行われないので、先日作った 👇 は static-import
っていう別名で NuGet パッケージを作って(!)dnx static-import
出来るようにしてみました。
駄文
良い感じなんだけど、今のところ dotnet は npx(npm)ほど普及していないのが悩ましい。Docker イメージにデフォで入ってないことが多いのでどうする? という印象。
標準ライブラリだけでほとんどの事が出来るのが .NET の良いところではあるんだけど、反面 SDK のインストールサイズが大きいってのはちょっとした用途には不向きって感じでしょうか。その点 node_modules が色んな所に溢れかえるけどインストールサイズが小さいのが Node.js の良いところ。(コミコミで100MB程度)
いっそのこと
npx dotnet -- package@x.x.x [options...]
で SDK インストールから実行まで出来るようにしちゃえばいいんじゃないですかね? 既にパッケージ名取られちゃってるけども。
(将来的には各環境向けにコンパイルされた軽量でネイティブコードな実行環境を配布! みたいなパワープレイで全部解決しそうだけど)
ネイティブ AOT
.NETツールは、1つのパッケージで複数のRuntimeIdentifier(RID)をサポートして公開できるようになりました。ツール作成者は、サポートされているすべてのプラットフォーム用のバイナリをバンドルでき、.NET CLIはインストールまたは実行時に正しいものを選択します。これにより、クロスプラットフォームツールの作成と配布がより簡単になります。
thx: DeepL 翻訳
こちら、サンプルで示されている ToolType
というオプションが追加された訳ではないという分かりづらさ。
dotnet pack -p ToolType=<variation> # 汎用的に使えないよ!
サンプルのリポジトリを見ると分かりますが、ハードコードされた <ToolType>
というプロパティーを C# プロジェクト側で確認してオプションを変えてるだけ。
<RuntimeIdentifiers>
で複数のターゲットを指定して dotnet pack
したら一括で~~とかもない。従来通り -r
または --use-current-runtime
で個別にパッケージングする必要がある。
サンプルの GitHub アクションには以下の形式でパッケージングされた .zip
がアーティファクトとして上がっているけど、
-
all-aot-packages.zip
- aot-package-agnostic/
<pacakge>.<version>.nupkg
- aot-package-ARCH/
<pacakge>.<ARCH>.<version>.nupkg
- aot-package-agnostic/
この構成だと dnx toolsay
で良い感じに AOT ランタイムを実行してくれるのかは不明。肝心の NuGet にパッケージがアップされていないので試せず。
static-import
で試そうと思ったけどネイティブ AOT コンパイルがリンカーでコケて断念。
ともあれ dotnet pack
で
- 良い感じにすべてのネイティブ AOT ビルドを一つの
.nupkg
(ZIPアーカイブ)にまとめてくれる
という機能は実装されていない。要するに dotnet pack
は何も変わっていない。多分 dotnet tool exec
側が .nupkg
内のファイルの中から良い感じにベストなモノを選ぶようになったって話でしょう。
最終的に一つの .nupkg(.zip)に全部のランタイムを纏めないとダメだと思うので dotnet pack
のアップデート待ちでしょうか。ライブラリ依存無しで実行できる .nupkg は配布サイズがヤバいのでうーーん? どこで使う? dnx だときつくね? って感じもありますが。
while ループの最適化
コレは Unity 等の古い環境でも(手動で)適用可能な最適化。
コンパイル結果としては以下の通り。(Unity 上で確認)
while(従来)
- 無条件ジャンプで while の条件判定に飛ぶ
- while ブロック内のコード群
- while の継続条件チェック(最初の無条件ジャンプで飛んでくる場所)
- while を抜けた後のコード群
if...do...while(最適化)
- while と同じ条件でチェックして false ならループを抜けた後にジャンプ
- do...while ブロック内のコード群
- do...while の継続条件チェック
- do...while を抜けた後のコード群(最初の条件分岐で飛んでくる場所)
従来方式だと while ブロック内のコード群を一回飛び越えてからまた戻る、ってコードパスを通る確率が高かったものがコードサイズを1バイト増やすことで改善されたって感じでしょうか。正直何が変わるの? ブロック内のコードサイズ次第? って感じですが BCL 全体に適用されると考えればデカそうです。
c/c++ 等の
while (true)
よりdo...while(true)
の方が良いよ、っていうコンパイラーが最適化されている現在では通用しない最適化が C# では未だ有効だった、的な話っぽい?
古い環境でも
👇 と同じでチューニングしまくれば最新の .NET 環境と同等の性能を引き出すことができるので、一応は覚えておきたいテクニックですね。(List のベンチマーク結果を参照のこと)
※ デカい SDK じゃなきゃやっても何も変わんないと思いますがw
おわりに
単一ファイルで実行できるアプリは夢が広がるけど npx で良いかなー感があります。.NET SDK インストールされてないですからね。あと2バージョン後ぐらいですかね。
以上です。お疲れ様でした。
Discussion