効率的な Go ―データ指向によるGoアプリケーションの性能最適化
https://www.oreilly.co.jp/books/images/picture_large978-4-8144-0053-9.jpeg
本書は、Go アプリケーションの効率や スケーリング に関する疑問に対して、実用的な答えを与えてくれる書籍です。 レイテンシー、CPU、メモリ資源 についての知識、また OS や Go がそれらを抽象化している方法について、またソフトウェアの効率に関わるデータ駆動な意思決定を行う事の意味や、計算量解析の手法、最適化 状況の例など、実用的なソフトウェアを開発する中での「効率」に関する知識を紹介します。 Go やその他のモダンな言語で書かれたプログラムを設計、作成、変更するソフトウェア開発者、また誰かが書いたソフトウェアを主に運用する DevOps エンジニア、SRE、シスアド、プラットフォームチームなどの読者が、いつ、どのように効率最適化を適用するかという問いに答えるための知識を身に付けることができるでしょう。 目次
訳者まえがき
序文
1.1 性能の背後にあるもの
1.2 よくある効率に関する誤解
1.2.1 最適化されたコードは可読性がない
1.2.2 そんな機能は必要ない
1.2.3 ハードウェアの高速化・低価格化
1.2.4 かわりに水平方向のスケールが可能
1.2.5 市場投入までの時間がより重要
1.3 実用的なコード性能を実現するためのカギ
1.4 まとめ
2. 効率的な Go 入門
2.1 Goについて知っておくべき基礎知識
2.1.1 命令型、コンパイル型、静的型付け言語
2.1.2 重要なコードベースを改善するために設計された
2.1.3 Google が統治、しかしオープンソース
2.1.4 シンプルさ、安全性、可読性が最高
2.1.5 パッケージとモジュール
2.1.6 デフォルトでの依存関係の透明性
2.1.7 一貫したツール
2.1.8 単一のエラー処理方法
2.1.9 強力なエコシステム
2.1.10 未使用のインポートまたは変数がビルドエラーを引き起こす
2.1.11 ユニットテストとテーブルテスト
2.2 高度な言語要素
2.2.1 第一級市民としてのコードドキュメント
2.2.2 後方互換性と移植性
2.2.3 Go ランタイム
2.2.4 オブジェクト指向プログラミング
2.2.5 ジェネリクス
2.3 Go は速いのか
2.4 まとめ
3. 効率化の攻略
3.1.1 合理的な最適化
3.1.2 意図的な最適化
3.2 最適化の課題
3.3 目標を理解する
3.3.1 効率化要件を定式化すべき
3.3.2 リソースを考慮した性能要件
3.3.3 効率目標の取得と評価
3.3.4 RAER の定義例
3.4 効率性にお悩みですか?冷静に!
3.5 最適化設計レベル
3.6 効率性を考慮した開発フロー
3.6.1 機能フェーズ
3.6.2 効率化フェーズ
3.7 まとめ
4. Go での CPU リソースの活用方法の(ちょっとした)解説
4.1 現代のコンピューターアーキテクチャにおける CPU
4.2 アセンブリ
4.3 Go コンパイラーを理解する
4.4 CPU とメモリウォール問題
4.4.1 階層型キャッシュシステム
4.4.2 パイプラインとアウトオブオーダー実行
4.4.3 ハイパースレッディング
4.5 スケジューラー
4.5.1 オペレーティングシステムのスケジューラー
4.5.2 Go ランタイムスケジューラー
4.6 並行処理の使いどころ
4.7 まとめ
5. Go でのメモリリソースの使用方法
5.1 メモリとの関連性
5.2 メモリに問題がありますか?
5.3 物理メモリ
5.4 OS のメモリ管理
5.4.1 仮想メモリ
5.5 Go のメモリ管理
5.5.1 値、ポインター、およびメモリブロック
5.5.3 ガベージコレクション
5.6 まとめ
6. 効率性オブザーバビリティ
6.1 オブザーバビリティ
6.3.1 レイテンシー
6.3.2 CPU 使用率
6.3.3 メモリ使用量
6.4 まとめ
7. データ駆動効率性評価
7.1.1 「推定」効率計算量
7.1.3 実践的なアプリケーション
7.2 ベンチマークの極意
7.2.1 機能テストとの比較
7.2.2 ベンチマークは嘘をつく
7.3 実験の信頼性
7.3.1 ヒューマンエラー
7.3.2 本番環境の再現
7.3.3 性能の非決定性
7.4 ベンチマークレベル
7.4.1 本番環境でのベンチマーク
7.4.2 マクロベンチマーク
7.4.3 マイクロベンチマーク
7.4.4 どのレベルを使うべきか
7.5 まとめ
8. ベンチマーク
8.1 マイクロベンチマーク
8.1.2 結果を理解する
8.2 マイクロベンチマークのヒントとコツ
8.2.1 分散が大きすぎる
8.2.2 自分のワークフローを見つける
8.2.3 正しいものをベンチマークをしよう!
8.2.4 チーム(と未来の自分)とベンチマークを共有する
8.2.5 さまざまな入力に対するベンチマークの実行
8.2.6 マイクロベンチマーク vs メモリ管理
8.2.7 コンパイラー最適化 vs ベンチマーク
8.3 マクロベンチマーク
8.3.1 基本
8.3.3 結果と考察を理解する
8.4 一般的なマクロベンチマークのワークフロー
8.5 まとめ
9. データ駆動ボトルネック分析
9.1 根本原因分析、ただし効率化のために
9.2 Goにおけるプロファイル
9.2.1 pprof 形式
9.2.2 go tool pprof レポート
9.3 プロファイルシグナルの取得
9.4 共通のプロファイル計装
9.4.1 ヒープ
9.4.2 ゴルーチン
9.4.3 CPU
9.4.4 Off-CPU 時間
9.5 ヒントとコツ
9.5.1 プロファイルの共有
9.5.2 継続的プロファイル
9.5.3 プロファイルの比較と集計
9.6 まとめ
10. 最適化の例
10.1 Sum の例
10.2 レイテンシーの最適化
10.2.1 bytes.Split の最適化
10.2.2 runtime.slicebytetostring の最適化
10.2.3 strconv.Parse の最適化
10.3 メモリ使用量の最適化
10.3.1 ストリーミングアルゴリズムへの移行
10.3.2 bufio.Scanner の最適化
10.4 並行処理によるレイテンシー最適化
10.4.1 素朴な並行処理
10.4.2 分配を利用したワーカーアプローチ
10.4.3 連携しないワーカーアプローチ(シャーディング)
10.4.4 ストリーム化されシャード化されたワーカーアプローチ
10.5 おまけ: 独創的に考える
10.6 まとめ
11. 最適化パターン
11.1 よくあるパターン
11.1.1 作業を減らす
11.1.2 機能を効率と交換する
11.1.3 空間を時間に交換する
11.1.4 時間を空間に交換する
11.2 3つのRの最適化法
11.2.1 割り当ての削減
11.2.2 メモリの再利用
11.2.3 リサイクル
11.3 リソースを漏らさない
11.3.1 ゴルーチンのライフサイクルをコントロールする
11.3.2 確実に閉じる
11.3.3 使い切る
11.4 できるだけ事前に割り当てる
11.5 配列でメモリを使いすぎない
11.6 メモリの再利用とプール
11.7 まとめ
11.8 ここから先へ
付録A ナプキン計算用のレイテンシー