MJHD

エモさ駆動開発

Railsにsorbetインストールしてみた with LSP

Rubyの静的型チェッカー、「Sorbet」がオープンソース化された。
LSPも実装されており、これだけRubyもシェアがあるので、覇権を握れるのでは。
手元にちょうど良いRailsプロジェクトが合ったため、導入してみた。

Sorbetのインストール

ここではあまり詳しく説明しないが、基本的には公式ドキュメントのGetting Started通りに進めていく。
Gemfileに追記し、bundle install、srb initをするぐらいで一瞬で終わった。

デフォルトではファイルの先頭に

# typed: false

と書いてあるため、型チェックはされない。
試しにここを

# typed: true

に変更してみると、例えばRailsのControllerなどでは大量にエラーが出るはず。

これは、Railsが実行時にroutingなど動的に様々なシンボルを生成しているためで、このままだと使い物にならない…。

Rails対応

sorbet-railsというRails向けsorbetの型定義生成ツールがある。
これを入れれば一通り開発ができるようになる。

インストールはこちらもREADME通りに進め、最後に

$ srb tc --suggest-typed --typed=strict --error-white-list=7022 --autocorrect

を実行すれば型チェックが実行可能になったファイルのtypecheck level(ファイルの先頭にあるtyped)を上げてくれる。

これにより先ほどはエラーが出ていたcontrollerなども

# typed: true

となり、型チェックが通るようになる。

LSP導入

せっかく静的型付けができるようになったので、LSPによる定義へジャンプや補完、型チェックを使いたい。
LSP導入の方法は色々調べたがドキュメントが全くなく、自己流で導入した。 (おそらく今後この辺のドキュメントも揃ってくると思う)

まずは、公式レポジトリをクローンする。

$ git clone https://github.com/sorbet/sorbet

次に、README通りにbazelや必要なライブラリのインストールを行う。macユーザで今までC++で開発をしたことがないユーザは、以下のコマンドも必要かもしれない。

$ open /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg

準備ができたら、bazelでビルドを行う。この時、プロダクションビルドのオプションを指定する。

$ bazel build //main:sorbet --config=release-mac (またはlinux)

これにより、bazel-bin/main/sorbet というバイナリができ上がる。

このバイナリを以下のようなオプションをつけて、プロジェクトのルートで実行するとLSPとして待ち受けるようになる。

$ sorbet --disable-watchman --no-config --enable-all-experimental-lsp-features--lsp --dir .

(--no-configを設定しているが、これは簡単のためであり、本来はプロジェクトごとの設定ファイル(sorbet/config)を読み込むべき)

これをvimVSCodeに設定すれば、補完や定義へジャンプが有効になり、快適なsorbetライフが送れるようになる。

Golangメモリ周りのメモ (mid-stack inlining編)

前回

mjhd.hatenablog.com

mid-stack inliningとは

mid-stack inliningとは、前回の記事でも紹介したインライン化をより積極的に行うようになる機能のことである。

前回の記事からの引用だが、

Goのコンパイラは、関数が以下の条件に当てはまるとき、関数を直接、呼び出し元に展開する最適化を行っている。(これも上のコマンドで解析結果を確認できる)

コードが80ノード以下(Go1.4以前は40ノード)
関数呼び出し、ループ、ラベル、クロージャ、panic、recover、select、switchなどの複雑な構文を含まない

以上がインライン化の大まかな条件であった。ここには、関数の呼び出しという項目があり、今まで関数のインライン化は一番末端にある関数(木構造でいう葉っぱ)でしかインライン化を行なっていなかった。
mid-stack inliningは、これを改良し末端以外の関数でもインライン化を行うための最適化である。

インライン化による弊害

これはmid-stack inliningの有効無効に関わらない話だが、インライン化により、スタックトレースを出力した際などに実際のソースコードとの差異が出てしまう。

例えば以下のような関数があったとする。

type s struct {
  c int
}

func a(v *s) {
    v.c++
}

func b(v *s) {
    a(v)
}


func main() {
    b((nil)(*s))
}

このコードがもしインライン化されたとすれば、以下のようなコードになる。

type s struct {
  c int
}

func main() {
    ((*s)(nil)).c++
}

ここでnil pointer dereferenceが発生した場合、以下のようなスタックトレースが表示されてしまう。

panic: nil pointer dereference

main.main()
        /main.go:16 +0x2

関数a, bの情報が消えており、デバッグが困難になってしまう。

どうやって解決するの?

mid-stack inliningでは、インライン化した関数のPCとソースコード上の位置を保持する木構造をテーブルとして表した構造体(InlTree)を生成し、シンボルテーブルに格納する。
実行時は格納されたテーブルから実際のスタックトレースを生成し表示を行うことで、インライン化をしたとしても正しく出力が行えるようになる。 ただし制限として、以下のように引数は省略されてしまう。

panic: runtime error: invalid memory address or nil pointer dereference

main.a(...)
         /main.go:8
main.b(...)
         /main.go:12
main.main()
        /main.go:16 +0x2

どのぐらい早くなるの?

ベンチマークによると9%ほどパフォーマンスが改善するらしい。
また、標準ライブラリにもコードを少し調整することでmid-stack inliningの恩恵を受けることのできる部分があるため、以下のような改善を繰り返していくことでGo全体のパフォーマンスが向上するのではと思う。

sync.Once.Do https://go-review.googlesource.com/c/go/+/156362/

sync.Mutex.Unlock https://go-review.googlesource.com/c/go/+/148958

参考文献

talk: Mid-stack inlining in the Go compiler (external) - Google スライド cmd/compile: enable mid-stack inlining · Issue #19348 · golang/go · GitHub proposal/19348-midstack-inlining.md at master · golang/proposal · GitHub

次回

mjhd.hatenablog.com

WSLのIO遅いよ問題

WSLは理論的にはLinuxカーネルを起動するオーバーヘッドがなく軽量に動作するはずなのだが、実際に動かしてみると色々ともっさりしている。
例えばnpm installなどが重たすぎて永遠に終わらなかったりエラーが出てしまったり。

この辺のもっさりは、WSLのIOが重いことに起因する。
www.phoronix.com

↓のスレッドではWSLのIOはなぜ遅いのか問題が議論されている。
github.com

SvenGrootさんの説明1

LinuxのIO操作とWindowsのIO操作の設計が根本的に違うことが原因。解決しようとしたら、Linuxの挙動を完璧に再現しなければならない。(例えば、Git for WindowsWindowsへポートされたプログラムだが、Windows用に挙動を変更することで対処している)
IO操作のパフォーマンスをあげる努力はしているが、WSLチーム(LxFSやDrvFSなどのVFS周り)、NTFSチーム、NTFSのフィルタ*1を実装する各ベンダ(Windows Defenderやサードパーティのウィルス対策ソフト)などの沢山の関係者がいて、複雑でとても進みの遅い作業になる。
例えば、Creator's Updateではstatコールのパフォーマンスを向上させる新しいファイルシステムAPIを導入した。そして、この変更を知らせ、使用してもらうために内外のベンダに働きかけている。
TL;DR: ファイルシステムのパフォーマンス問題は難しい、けど改善を続けてくよ。苦しみはわかるけど問題を無視してるわけじゃないよ。

注: 大まかな訳
https://github.com/Microsoft/WSL/issues/873#issuecomment-391810696

*1: ファイルのIOにサードパーティが独自の処理を挟めるもの。Windows Defenderはこれを使ってファイル変更の監視をしている

SvenGrootさんの説明2

ここまでの問題は簡単に言えば、"NTFSは遅い"か"DrvFSは遅い"だと思う。
IOサブシステムはWindowsLinuxでかなり違う設計になっている。大きな違いは以下の3点。

  1. Linuxはトップ階層にキャッシュを持っていて、キャッシュに存在するエントリに関してはFS内部を探索しなくても返すことができる。 Windowsにはこのようなキャッシュがなく、ファイルシステムに大きく頼っている。Win32の「C:\dir\file」のようなパスは「\??\C:\dir\file」というNTパスに変換され、「\??\C:」部分はObjectManagerが管理する\Device\HarddiskVolume4などへのデバイスオブジェクトへのシンボリックリンクを表している。
    一度このようなデバイスオブジェクトを発見すると、Windowsは残りのパスを単純にファイルシステムへ託す。ここがLinuxVFSが行うような中央集権的なパス解析との違いである。

  2. WindowsのIOスタックは拡張性を重視しており、ファイルシステムへのIO操作要求を実行する前にフィルタドライバを設定することができるようになっている。これは、例えばウィルススキャン、圧縮、暗号化、OneDriveのような仮想的なファイル、アプリの起動高速化のためのpre-fetchingなどなど至る所で使われている。Windowsクリーンインストールしたとしても、すでにWindowsはある程度の数のフィルターが特にシステムドライブ(C:)に関しては動いている。(なのでD:ドライブや他のパーティションが存在するマシンなら、よりフィルタが少ない傾向にあるシステムドライブ以外を使うことを推奨する)
    これらのフィルタは沢山のIO操作、特にファイルのオープンと作成に設定されている。

  3. NTのファイルシステムAPIはパスベースではなく、ハンドルベースで設計されている。なので、ほとんどいかなる操作もはじめにファイルを開きハンドルを取得する必要があり、この操作はパフォーマンスに影響する。例えば、Win32 APIでファイル削除の1コール(DeleteFileなど)を実行したとしても、実際にはOpen/Close操作が走っている。少し前にリリースしたDrvFSの大きな改善は、ファイルの情報取得のためにファイルを開かなくても良い新しいAPIを用意することだった。

基本的にファイル操作はLinuxよりもWindowsの方が重い。とりわけファイルのメタ情報に触れる操作は。
これらの重さの原因はObjectManager*1やIO Manager*2、フィルタ、そしてNTFSに広がっている。
単純に「NTFSが遅い」というだけならNTFSの最適化の修正を行えば良いが、問題は広大なコンポーネントに広がっており、銀の弾丸がない状況である。
また、内製のフィルタだけならまだいいが、サードパーティのフィルタが内部で何を行なっているかは知るすべがないので、各ベンダと共にこれらの問題の改善を試している。例えば、ファイル情報を取得する新しいAPIを導入し、フィルタドライバもそのAPIをサポートした時、まだ新しいAPIに対応していないフィルタがインストールされていたとしても正常に動作することを保証しなければならなかった(基本的にはOpen/Query/Close処理へフォールバックする)。その他もこれをサポートしていることを確認し、最大のパフォーマンスの恩恵を受けられるようにするためには沢山の時間と労力がかかった。
同じことが大文字小文字を区別するディレクトリなどにも言え、変更後の動作をフィルタのエコシステムが正常にハンドルできるのか確かめなければならない。

...中略...

また、単純に「Windowsが遅さの原因」と言うわけではなく、WSLの影響もある。特に、WindowsLinuxのパス解析の挙動の大きな違い(Linuxは中央集権、上でも述べた通りWindowsファイルシステムに任せている)がある。LinuxアプリはLinuxの挙動を想定して作られている。なので我々も慎重にその挙動をエミュレートし、不幸なことにも沢山のIO操作をファイルシステムに送ることになってしまっている。例えばstatコールも、Linuxはキャッシュ*3にヒットさえすればLinuxカーネルが全体を応答するが、WSLではフィルタ全体を走査する複数のリクエストをファイルシステムに対して送らなければならない。
我々はWSLで余計な処理が必要にならないよう沢山の作業を間も無くリリースされる1809で行なった。
だけど、LinuxWindows APIが違う以上、ここにはどうしても余計な処理が必要になってしまう。

基本的には、これは単純な問題ではなく、沢山のコンポーネントが関わっていて、フィルタ機能に変更を加えるならMicrosoft's Partnersと共に取り組んでいかなければならない問題である。
かといって諦めるわけではないよ〜。

注: 大まかな訳
https://github.com/Microsoft/WSL/issues/873#issuecomment-425272829

*1 ObjectManager: オブジェクト(Windowsにおけるリソースの単位)を管理するコンポーネント
*2 IO Manager: 外部入出力を管理するコンポーネント。IRP(上で言うファイル操作のリクエスト)を送信する先
*3 dentry cache: ファイル情報を格納するdentryをメモリ上にマップでキャッシュしたもの

まとめ

  • WindowsのIO操作はLinuxより高価
    • フィルタ機能という拡張性を持たせている
    • Linuxカーネルのように中央集権のcacheを持たず、パスの解析からFSに任せている
  • パフォーマンス改善の取り組みは、社内複数チーム、サードパーティと登場人物が多く、労力と時間がかかる
  • Linuxを前提に書いたIO中心のプログラムはWSLで死ぬかも

There's a reason we have made it clear from its initial release, that WSL is not built for hosting production services/workloads ;)

WSLはプロダクションサービスやワークロードをホストするために作られたんじゃないよとリリース当初から明言している

2019年最高のWSL環境を求めて

環境のスクショ

2016年、僕はWSLに出会い感動してからというもの、「最高のWSL環境を求めて」さまよい続けました。
来る日も来る日も「Windowsは最高・・・Windowsはクソ・・・Windowsは最高・・・」と呟きながら花びらを散らし、バグのあるWindowsアップデートにも負けず、急に唸りだすRuntimeBrokerたちにも負けず、費やした時間は数知れず。
時にはディストリビューション壊して再インストールして、時にはHyper-Vに浮気をしたり、時にはiMacを買ってそっちに逃げたりしながら・・・。
今回は2019年、僕が「最高」だと思うWSL環境をまとめたいと思います。

過去の記事
mjhd.hatenablog.com

Xサーバ

LinuxGUIアプリケーションを表示するために必要なXサーバ、以前はVcxsrvを使っていましたが、現在のおすすめはX410です。
シェアウェアだけあってとても安定しています。とりあえず入れとけば完璧に動く、という安心感は他にありません。
今なら4700円割引(ほんとか)らしいです。

www.microsoft.com

ターミナルエミュレータ

ターミナルエミュレータはwslttyを使ったりX11経由でgnome-terminal, tilixなどを使っていましたが、やはり機能面と安定感の両立がなかなかできませんでした。
wslttyは機能面・デザイン面で劣るし、gnome-terminal、tilixなどをX11越しで使うのはIMEの設定が必要であったりクリップボードが安定しなかったり起動がもたついたり、なかなか満足いく体験には至りませんでした。

現在はalacrittyを使っています。
alacrittyはGPUを使用した高速なレンダリングが特徴の端末で、マルチプラットフォームなので機能面での不足はあまりありません。Rustさまさまです。
描画がとにかく早いので、WSL上でzsh使ってももたつきがほとんどないです。マジで早い。

Windowsの場合、初回起動時に「ホームディレクトリ\AppData\Roaming」以下に「alacritty/alacritty.yml」ファイルができるので、いい感じに設定してあげてください。
「alacritty theme」で検索すれば有名な色設定をコピペできます。
ConPTYの設定項目をtrueにしておくと良いです。
Microsoftも頑張っています。

https://cloud.githubusercontent.com/assets/4285147/21585004/2ebd0288-d06c-11e6-95d3-4a2889dbbd6f.png

github.com

あと、Terminus、FluentTerminalという端末もモダンでWindows10らしさがあって良いです。が、まだ発展途上ということもあり、特にパフォーマンスの観点でオススメできません。今後を見守りたいです。

https://github.com/felixse/FluentTerminal/raw/master/Screenshots/terminal.jpg

https://github.com/Eugeny/terminus/raw/master/docs/readme.png

Terminus

GitHub - felixse/FluentTerminal: A Terminal Emulator based on UWP and web technologies.

今後の改善点

やはりWSL最大の不満点は、Windows側からWSLのFSをいじれないことでしょう。
しかし、ここもMicrosoftは頑張っていて、UNIXドメインソケットを実装したことによりWindowsとWSL間の高速で汎用的な通信が可能になり、これを通してファイルを共有するという機能が盛り込まれると発表しています
(このアップデートが入るまではsftpやftpで共有するぐらいしか手段がなかった。samba動かんし。Dokan使ってマウントしたり)

WindowsからWSL側のファイルシステムが気持ちよく触れるようになれば、例えばWindowsネイティブのIDEからWSL上のプロジェクトを開き、ビルドなどはWSL上で行う、といったシームレスな開発ができるようになる予感がしています。
まだまださまよい続ける必要がありそうです。
Microsoft頑張って。

サウナー用語

この頃サウナにはまっており、話題のサービス「サウナイキタイ」のサウナー達によるレビューを読み漁ってたらなんとなくサウナー用語(サウナスラング)がわかってきたのでまとめる。

外気浴

人間の三大欲求の一つ。

サウニング

サウナに入ること。また、サウナ->水風呂->休憩のサイクルを繰り返すこと。

ライドオン

サウナ施設に突入すること。

SEO耳栓

SEOの辻さんが装着している耳栓

サ飯

サウナ施設や近所で食べられるご飯のこと。主にサウナ後の空腹状態で食べる。

サ室

サウナ室のこと。広さや設備、温度が語られることが多い。

アフターサウナ

サウニングが終わった後のこと。

ととのう

サウナによってある種のトランス状態に入ること。
または、自律神経が整うこと。(こっちの方が本物な気がする)

ととのいポイント

サウナ外にあるデッキチェアなど、サウナ->水風呂の後に精神統一できるスペース。

北欧

「上野サウナ&カプセルホテル北欧」のこと。「北欧に行く」と行ったら旅行に出かけるわけではなく、「上野サウナ&カプセルホテル北欧」で外気浴を満喫することを指す。

聖地

静岡にある「サウナしきじ」のこと。全国からサとりを開くためにサウナーたちが集まる聖地。水風呂に浸かると「宇宙が降りてくる」らしい。

緑のラッコ

草加健康センター。チンピリと広いサウナ。看板に緑のラッコが。
関連: ラッコイン, 草加健康センターへ行くこと。

ストロング系

温度設定の強めなサウナ、水風呂のこと。

はごろも

水風呂に浸かってしばらくすると皮膚の周りに出来上がるぬるい水の膜。水流が当たるとはごろもが取れるため、冷たく感じる。

グルシン

水風呂の水温が一桁台(シングル)であること。

バイブラ

浴槽内に設置される泡を放出する機械。水風呂内に設置された場合、体感温度が下がる効果がある。

チラー

水風呂において、循環した水を冷やすための機械。これが効いてないと人が入るたびにぬるくなっていく。

ニルヴァーナ

悟りを開くこと

2018年買ってよかったもの

年の瀬なので2018年に購入したものの中で、買ってよかったものをまとめてみた。

1位. ミラーボール

友人との会話の中でふざけて購入したミラーボールが思いのほか生活に潤いを与えてくれている。
このミラーボールは音に反応して光る機能があり、通常は流れている音楽のテンポに合わせて光らせる用途に使うらしいのだが、この機能が思いのほか日常生活で役立つ。
使い方としては、部屋の天井に装着し、音楽に合わせて光るモードを常にONにしておく。
例えば、友人を部屋に招いておしゃべりをするとき、話が盛り上がり、笑い声が出る。すると笑い声に反応してミラーボールが回りだす。それを見て笑いが止まらなくなる。ミラーボールは回り続ける。死ぬほど笑える。
意外性も高いため、今年1位。

2位. Surface Pro 6

今まで使っていたXiaomi Notebook Air 13を友人に売り、Surface Pro 6を購入した。ラップトップとしても、タブレット端末としても使える2-in-1。これを購入して家での過ごし方が変わった。
今までは、机にラップトップを置いておき、プログラミングなどの作業をする場合は机に向かう、机に向かうのに飽きたらソファーに座りスマホを触る、という過ごし方をしていたのだが、これがすべてSurfaceに置き換わった。
SurfaceはTypeCoverを外せばタブレット端末として使えるため、机から離れるときはTypeCoverさえ外せば自由に持ち運ぶことができる。
例えば、プログラムを書いていてビルド待ちの間TypeCoverを外し、ソファーに寝転がってビルドの進捗を確認しながらYoutubeを眺める、などといったことができるようになった。
性能も、i7 8650U 1.9~2.11GHz、メモリ16GB、SSD 512GBと通常のラップトップPCとしても申し分ない。
また、スピーカーも疑似サラウンドに対応していたり、ディスプレイの発色が良かったり、マルチメディアを楽しむうえでも十分なスペックがあると思う。
Surface Pencilは要らない。自分のような字が下手で絵も描けない人はミミズの絵を量産して飽きる。

3位. Qi充電器

充電が遅そう、劣化しそうなどのイメージがあったため使ってこなかったQi充電器だが、試しに使ってみたところ完全にハマった。普段使ってるのはiPhoneとAppleWatchを同時に充電できるタイプの充電器。
現在はオフィスと家にひとつづつ置くことで、充電ケーブルを持ち歩かない生活を送っている。ケーブルがないだけでデスク上も持ち物もかなりすっきりした。

4位. Philips Wake-Up Light

光で目を覚ましてくれる目覚まし時計。物は試しと思って買ってみたが、iPhoneのアラームで起きる2倍は目覚めが良い。
この目覚ましは、設定時刻の30分ほど前からゆっくりと明るくなっていく。この光によって半分覚醒している状態で設定時刻を迎えることができる。
設定時刻になると、鳥のさえずりの音声が流れだし、徐々に音量が大きくなっていく。 とはいえかなり小さい音、初めはこの音量じゃ起きれないだろと思っていたが、半分覚醒している状態のためこの音量でも十分起きることができた。起きれなかったことは一度もない。(ただし起きれても遅刻はする)
iPhoneのアラーム、強引に覚醒させるため、実はかなり健康に良くないんじゃないかと思うようになった。

5位. NILS

Kickstarterのプロジェクトだが、腕に取り付けることのできる充電ケーブル。
Qiで充電ケーブルを持ち運ばない生活を手に入れることはできたが、終電逃してネカフェなど、いざというときにUSBポートはあるのに充電できないという事態がたまに起こる。
そういう場合の対応策として、普段はアクセサリとして腕に装着しておき、いざというときに充電ケーブルとして使用することができるNILSを購入した。

www.kickstarter.com

今年もお世話になりました。

Golangのメモリ周りのメモ

以前、このレポジトリがバズっていた。

GitHub - intel-go/bytebuf: Example of how CL133375 can be utilized to mitigate Go escape analysis limitations.

bytebufが小さなサイズのバッファ用にあらかじめ用意しているbootstrapというバイト列が、エスケープ解析の際に必ずヒープ上に確保されてしまうため、buffer構造体も本来はスタック上に確保できるはずであるが、ヒープ上にエスケープされてしまうという問題があった。
つまり、64byte以下の小さなバッファであっても必ずヒープ上にアロケーションが走ってしまい、パフォーマンスが落ちていた。

この件は既にパッチが当たっており、正しくエスケープがされるよう修正されているのだが、これをきっかけに「なんでヒープに確保することが重たいんだっけ」「どういうときにエスケープされるんだっけ」などのメモリ周りを調べたメモ。

なんでヒープ確保が重たいの

スタックの確保はとてもシンプルで、関数呼び出し時にスタックを伸ばし、関数を抜けた時点でスタックを縮める。
比較して、ヒープ上へ確保する場合は、確保先の探索、GCなど様々な処理が走り、この差がパフォーマンスに効いてくる。
他の関数で参照される、参照を取得する必要があるといった場合を除き、極力エスケープしないようなコードが高速に動作する。

エスケープされる条件

基本的には、

  • 関数内のみで参照される値は、スタック上に確保される
  • そうでないものは、ヒープ上へ確保される

のだが、コンパイラが途中で解析を止め、エスケープする条件が複数ある。

この条件は日々変更が入ったり、今回のような特定の条件下で異なる動作をする場合があるため、網羅することはできないが(本来プログラマが意識するべきではないが)、2015年の時点で以下のリンクなどにまとまっている。

Go Escape Analysis Flaws - Google ドキュメント

Goの公式ドキュメントを読んでも「すべての条件を説明するのは複雑すぎるので、コンパイルフラグで実際にエスケープされるか確認して」と書いてある。 以下のコマンドで確認することが出来る。

$ go build -gcflags '-m' ./main.go

CompilerOptimizations · golang/go Wiki · GitHub

関数のインライン化

直接関係はないが、エスケープ解析に効いてくる最適化の一つに、関数のインライン化の解析がある。

Goのコンパイラは、関数が以下の条件に当てはまるとき、関数を直接、呼び出し元に展開する最適化を行っている。(これも上のコマンドで解析結果を確認できる)

  • コードが80ノード以下(Go1.4以前は40ノード)
  • 関数呼び出し、ループ、ラベル、クロージャ、panic、recover、select、switchなどの複雑な構文を含まない

CompilerOptimizations · golang/go Wiki · GitHub

このインライン化がどうメモリ周りに効いてくるかというと、インライン化が無い場合、関数の引数に値を渡した時点でその値はヒープ上に確保されてしまう。 しかし、インライン化された関数であれば、関数内での値の使用となるため、スタック上の確保で済む。

別の記事で、この最適化を意識したコードの例を考えてみたいと思う。

参考

CompilerOptimizations · golang/go Wiki · GitHub

najeira: Go言語のスタックとヒープ

Escape-Analysis Flaws

Allocation efficiency in high-performance Go services · Segment Blog

次回

mjhd.hatenablog.com