フューチャー技術ブログ

Go 1.16連載が始まります

毎年2月と8月はGoの新バージョンがリリースされます。2021年2月は1.16です。本ブログでは1.16のリリースを記念してGo 1.16の新機能を紹介する集中連載を行います。現時点のリリースノートはこちら。次のような内容を考えています。乞うご期待。

公開日 寄稿者 記事
2月8日 伊藤真彦 Go 1.16からリリースされたgo:embedとは
2月9日 真野隼記 Go 1.16のgo installについて
2月10日 辻大志郎 Go1.16からのio/ioutilパッケージ
2月12日 澁川喜規 Go 1.16のsignal.NotifyContext()

本エントリーは、これら以外にどんな変化があったのかをダイジェストで紹介します。

アーキテクチャ対応: M1のmacに対応

今回も新しいアーキテクチャの追加が行われていますが、一番大きいのはApple Siliconの正式対応でしょう。2ヶ月ほど前に対応コードがmasterにマージされたタイミングで当ブログでもすでに紹介していました。

もともとdarwin/arm64はiOS向けでしたが、これはios/arm64にリネームされました。c-archive, c-shared, pieモードも使えるし、race detectorも利用可能です。

すでに計測値を出していましたが、Rosetta以外をRC1で再計測してみました。M1は高速な結果から、さらに全体的にはすべての結果が1割近く改善していました。amd64は処理系が安定していて、差があっても誤差かな? というものが多かったです。いくつか、M1が他のCPUに負けていた項目だけピックアップしたのが次の表です。他のものより8倍遅かったCRC32は4倍改善され、2倍遅いぐらいで差が詰まっています。ParseBoolは1割ほど高速したものの、他との差は大きいですね。SHA1とSHA256は大幅改良で他を圧倒する速度を手に入れています。全体的に他のCPUとの差をさらに広げつつ、負けているところもかなり減ってきていますね。残っている大負けしているテストはrosetta2にも負けているということでGoのランタイムのコードが改善されたら治るはずで、M1のハードウェア起因ではなさそうですね。

M1 (12/3のmaster→RC1) M1(rosetta) Core i5-1030G7 (12/3のmaster→RC1) Ryzen 9 4900HS (12/3のmaster→RC1)
BenchmarkBlake3256-8 6339→5733 エラー 3460→3764 2782→2849
BenchmarkCRC32-8 1098→255.5 139.2 140.5→143.5 163.7→169.8
BenchmarkFnv128-8 4924→4465 7617 3448→3598 6084→6026
BenchmarkMD5-8 3566→3198 4345 3283→3209 2635→2603
BenchmarkSHA1-8 5789→899.9 4247 2924→3177 2041→2086
BenchmarkSHA256-8 10865→914.8 7832 6361→6473 4346→4612
BenchmarkSHA512-8 7801→6997 3987 4685→4816 2939→3224
BenchmarkMathAtomicInt32-8 7.132→6.888 7.864 6.562→6.015 4.258→4.149
BenchmarkMathAtomicInt64-8 7.07→6.918 7.758 7.079→5.890 4.231→4.167
BenchmarkMathMutexInt-8 12.45→13.68 15.07 18.69→15.58 8.776→8.589
BenchmarkParseBool-8 1.598→1.430 0.3529 0.3532→0.3147 0.3208→0.5364

VSCodeも1.53でInsiderでない安定板もM1対応になりますし、GoLandもネイティブ版がリリースされました。Rosetta2でも快適だった環境はますます快適になっています。

それ以外だとlinux/riscv64対応が改良されていて、個人的には気になっています。

ランタイムの変化

runtime/metricsパッケージが導入されました。runtimeとかdebugとかさまざまな場所に散っていったメトリックス収集機能が集約されました。今サポートしているのはGC関連のメトリックスと、メモリ関連のメトリックス、goroutine数ですね。

あとは、GODEBUG環境変数にinittrace=1を設定すると、各パッケージのinitで消費している時間やメモリの情報が標準出力に表示されます。Google App EngineやらCloud RunやらCloud FunctionsやらAWS Lambdaやらでインスタンス数ゼロからのコールドブート時間を減らしたいサーバーレス愛好家にとってはタピオカミルクティー🧋並に人気が出そうな新機能です。

init compress/flate @1.2 ms, 0.027 ms clock, 4240 bytes, 7 allocs
init hash/crc32 @1.2 ms, 0.014 ms clock, 1024 bytes, 1 allocs
init compress/gzip @1.2 ms, 0.022 ms clock, 32 bytes, 2 allocs
init runtime/pprof @1.3 ms, 0.018 ms clock, 32 bytes, 2 allocs
init crypto @1.3 ms, 0.019 ms clock, 160 bytes, 1 allocs
init crypto/md5 @1.3 ms, 0.001 ms clock, 0 bytes, 0 allocs
init crypto/sha1 @1.3 ms, 0 ms clock, 0 bytes, 0 allocs
init crypto/sha256 @1.4 ms, 0 ms clock, 0 bytes, 0 allocs
init crypto/sha512 @1.4 ms, 0 ms clock, 0 bytes, 0 allocs
init math/rand @1.4 ms, 0.059 ms clock, 5440 bytes, 3 allocs
init golang.org/x/sys/cpu @1.5 ms, 0 ms clock, 0 bytes, 0 allocs
init github.com/zeebo/blake3/internal/consts @1.5 ms, 0 ms clock, 0 bytes, 0 allocs
init golang.org/x/crypto/blake2b @1.5 ms, 0.019 ms clock, 32 bytes, 2 allocs
init golang.org/x/crypto/sha3 @1.5 ms, 0 ms clock, 0 bytes, 0 allocs
init main @1.5 ms, 0 ms clock, 0 bytes, 0 allocs

ツールの変化

go.mod対応周りが大幅に変わったことと、embed対応が大きなトピックです。これはそれぞれの紹介のなかで詳しく説明されます。

1.15で加えられたリンカーの更新がELFベースのOS/amd64だけだったのが、ありとあらゆる環境に適用され、速度は20-25%高速に、メモリ使用量は5-15%ほど削減されています。

それ以外は比較的小さい変化で、go testで、os.Exit(0)もエラーとなるように変更されたりとかですかね。あとは-overlayでファイルのパスの読替のJSONを読み込ませることができ、ファイルの動的な置き換えが可能になるという変更もありますが、これは未セーブのファイルを別のパスに書き出しておいてデバッグ実行するといったように、エディタ側から使われることを意図しているようでした。

1.16でレジスタベースの関数呼び出し規約が入ってパフォーマンスアップというのを報じるメディアもありましたが、それは1.17に先送りされたようです。次も楽しみですね。

ライブラリの変化

全部を紹介するのは細かすぎるので、気になるポイントだけピックアップします。

大きいのはembed追加に伴って導入されたio/fsと、io/ioutilが非推奨化されたことですね。リリースノートで大きく取り上げられています。また、いくつかのパッケージがio/fs対応で機能追加されています。

また、小さい関数追加のsignal.NotifyContext()は個人的にうれしかったので連載で取り上げます。

netパッケージではErrClosedというエラーのインスタンスが追加されました。1.13でerrorsパッケージが更新されてエラーチェックの共通の方法としてerrors.Is()が導入されましたが、それとの比較が行いやすいように、いままで非公開だったエラーのインスタンスが公開されました。新しく提案された使い方に合わせて、全体が統一されていくのは良いですね。

strconvのParseFloat()は新しいアルゴリズムを使うことで最大二倍高速になりました。これを使っているencoding/jsonも高速になるとのこと。

time/tzdataがスリムなデータ構造を使うようになってバンドルサイズが小さくなったとかもありました。

個人的に面白かったのがコードのパーサーのライブラリの更新で、Go 1.17で導入予定の新しいbuild constraintのコメント形式をサポートするというものです。Go 1.17のソースを処理するツールを今から書けますよ、とのこと。

// 今の書き方
// +build syntax

// Go1.17の書き方
//go:build

おまけで、Unicodeのバージョンが13になりましたので、ランタイムのところに書いた↑タピオカミルクティーの絵文字🧋がGoで使えるようになりました。

1.17以降の変更

すでに説明した関数呼び出しのレジスタベースの関数呼び出しでパフォーマンスアップが計画されています。

注目度が高いジェネリクスは今のところ2022/02の1.18ぐらいになると言われていますが、ジェネリクスのプロポーザルが2/4にlikely acceptフェーズになりました。Goのワークフロー的には「ディスカッションがコンセンサスに到達。最後のコメントを受け入れる期間」となっています。かなりリリースが近づいてきていますね。

2/11更新: 1週間たって、ジェネリクスのプロポーザルがacceptedなりました