宿題レビュー

func Perm ランダムに添字を作ってくれる

擬似乱数 rand.Seed は毎回やるのは無駄になる

パッケージ変数は短くしない。1文字にするのはブロックスコープの変数。

エラーはos.Stderrへ

並行処理

ゴールーチンとConcurrency

  • スレッドみたいなやつ。実際にはスレッドの上でゴールーチンが動く
  • プログラムが起動すると、最初にmainゴールーチンが動く
    • ゴールーチンリーク ゴールーチンが永遠に動き続ける。
    • サーバーで動かしていると起こりがち。

チャネル

func main() {
	var v int
	go func() {// ゴールーチン-1
		time.Sleep(1 * time.Second)
		v = 100
	}()
	go func() {// ゴールーチン-2
		time.Sleep(1 * time.Second)
		fmt.Println(v)
	}()
	time.Sleep(2 * time.Second)
}

time.Sleep は実際は良くない。危ない。

  • 競合を防ぐ方法

    • チャネル
    • ロックを取る(syncパッケージ)
  • バッファ

    • チャネルにバッファを指定しないと初期値は0
    • 送受信時の処理のブロック
    • チャネルにおけるデータのやり取りを保証できる
  • チャネルの変数は関数をまたいで共有しても競合は起きない。

  • select

    • Channel が複数の場合に使用
    • Select, case, default
    • default は意外と使用すr。
      • select と default だけのパターン。チャネルの値をチラ見したいケースなど。
      • select にcaseを書かないとブロックし続ける。
    • Case: nil
      • 何もしない。
      • 処理を休む時などに使用。
  • ファーストクラスオブジェクト

    • Chan の chan
    • コールバックでたまに使う
      • 何かあった時はこのチャネルを使ってくださいね、という時
    • <-time.After(5 * time.Minute)
    • 受信専用のチャネルを返す。
    • よくわからん人は自分でtime.Afterを作ってみる。time.Sleepを使えばできる。
    • 双方向 or 単方向
  • Concurrency の実現

    • gorouitneは実務で激し使用する訳ではないが、慣れが必要な
    • race conditionをテストで発見することが大切
    • gotraceGoroutineを可視化するツール
    • 参考

    • goroutineの数を表示するなどして、リーク、raceを防止する

    • testcaseで把握するのが理想だが、実際は難しい。異常系が原因によることが多いため

syncパッケージ

  • ロック、sync/atomicによるアトミックな演算

  • sync.Mutex

    • Lockメソッドを呼んだ際に、Unlockされるまでにブロックを担保してくれう
  • 読み込みが多い場合、Mutexは無駄になってしまう

    • RWMutex を使用する
  • WaitGroup

    • 複数のゴールーチンを待ち合わせる
    • Addした回数と同じ数だけDoneするまでブロックする
  • errgroup

    • エラーが発生した時にエラーチャネルを返すのが手間。それを防ぐ。
  • sync.Once

    • goroutineがどういった関数から実行されるはわからない。なので、一回しか実行されないように、限定する

    • Panic に注意、下はいけない。recoverは一つのgorounine内でのみ

    • func main() {
      defer func() {
          recover
      }()
      go func() {
          panic("guha")
      }
      select{}
      }
      
      • リンク

      • チャネルのClose

      • 基本的には送信側が閉じる。放っておいても基本的に良い。明示的に閉じたい時たい時だけとじろ

      • 二度閉じることは不可。

      • 閉じられたチャネルには送信できない。panicが起きてしまう。なので送信側のみCLoseを行う。

      • リーク防止のためにCloseを利用する。一つCloseすれば、全てのチャネルに伝わる。

      • コンテキストでCloseは使われることが多い。

      • コンテキスト

      • ゴールーチンに文脈を持たせる

      • コンテキストという名前のものが沢山あるが、context.contextが一番使う

      • Go1.6を境に、contextが準標準から標準に移行。

      • withcancel キャンセルできるコンテキストとして初期化する

      • Background ルートを作る

      • cancel を呼ぶと子供のゴールーチンにもキャンセルが伝播するので便利。

      • つまり、Context.Doneを使うことで、リークを防止できる。

      • 一定の時間が経ったらキャンセルすることを担保してくれるのが withTimeout.

      • 外にリクエストを投げる時、時間でタイムアウトを持たせたい時に便利。

      • WithValue

      • goroutineの間で値を共有できる。

      • 例 キャッシュを無視できるように、値を持たせてやる

      • エンプティstruct{}

      • 容量を消費しないので、引数になどに使った場合、送ったことだけを伝えることができる。

      • コンテキストは引数で回すことが多い

      • ラップされるので、値が変わる可能性があるため、フィールドに保存しない

      • ゲッターとセッターを両方作る

      • 便利なグローバル関数としてはいけない。限られたデータのみ保存

      • rangeはチャネルにも使える。値をとるまで回し続ける。

      HTTPサーバとクライアント

      • Handlerの登録は一箇所でやったほうが見通しが良い
      • http.ListenAndServe(":8080", nil)としてnil を指定すると、DefaultServeMux が当たる。その中でルーティングしている感じ。
      • gollira Mux RESTのルーティングに便利。メソッド GET POST の切り替えが良い感じ
      • net.JoiHotPort(host, port)
      • host + ":" portとはしない。JoinHOstPortではIPv6の時の挙動もよろしくやってくれるので。
      • 構造体のタグ… JSON化する時
      • フィールドのアノテーション
      • 言語仕様上、書き方の記法は決まっていないが、デファクトあり
      • go のフィールド名とJSONのフィールド名を別にすることも可能
      • テンプレート
      • html と textの2種類がある
      • 実際はテンプレートは使わない….
      • テンプレートエンジン自体は、テキストテンプレートの場合は使う
      • コマンドラインツールの出力の形式を変えたい場合などに使う
      • ミドルウェア
      • ハンドラより前に行う共通処理
      • コンテキストに値を詰め込む
      • アクセスログを出す
      • 認証処理 など
      • ライブラリもあるが、そんなに手間なくスクラッチで作れる
      • Net/httpのパッケージという訳ではない。一から作ろう
      • インターセプター
      • ミドルウェアと同じような感じ

      • net/http/httptest

      • ハンドラのためのテストを提供

      • ハンドラは戻り値を返さない。ライターに書き込む。なので、ライターにhttptest.NewRecoder()を当ててやり、結果を見る。

      • Client

      • DefaultClient を直接書くことはしない。 自分用のクライアントをちゃんと作っておいたほうがよい。

      • http.CLient.Do

      • 名前がシンプルで良いのはGoの文化

      • http.Transport

      • 実際はhttp.ClientではなくTransportが重要な役割を担っている。

      • 実際にHTTP通信を行うところ

      • http.DefaultTransport

      • http.RoundTripper

      • http通信をやらずにGRPCをやる時などに、この辺りを弄っていたりすることがある。

      • リクエストの前の前処理、後処理、モックサーバーを作りたい場合などに使う。

      • テストの時だけ url を差し替えたい時などに便利

      ##DB

      • ドライバはサードパーティ

      • sql.Open 引数の値は、DBによって異なる

      • Exec, Query, QueryRow

      • Rows.Next() 次のidをforで回して順に持ってくる

      • Rows.Scan でフィールドに落とし込む

      トランザクション

      • Begin(), BeginTx()

      ORM

      • 中でリフレクションを使うため、実行時に重たくなる
      • Xo/xoはコンパイルの前に実行するので、一回やっておけば重くない
      • mercari の yo も同じ
      • スパナに関してはSQLDBパッケージを使えない GOogleが使ったライブラリがあるので、それを使用する
      • mercari/datastore

      • xo/xo

      宿題

      • おみくじテスト
      • 正月のモック
      • ハンドラのテスト 現在時刻のごまかし

      LT

      connpassから申し込むこと