Gopher道場4回目

   · ☕ 6 min read
🏷️
  • #go
  • 宿題レビュー

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

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

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

    エラーはos.Stderrへ

    並行処理

    ゴールーチンとConcurrency

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

    チャネル

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    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内でのみ

      • 1
        2
        3
        4
        5
        6
        7
        8
        9
        
        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から申し込むこと

    Share on

    whasse
    WRITTEN BY
    whasse
    Web Developer