関連記事
Goメモ-498 (シンプルなラッチ)(CountdownLatch, CountdownEvent) - いろいろ備忘録日記
GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ
概要
以下、自分用のメモです。
前回、ラッチについてのサンプルをメモしたので、ついでにゲートもメモ。
カウント1のラッチは、単純なオン/オフのラッチとなり、ゲートとして機能します。
サンプル
countdownlatch.go
以下を参照ください。
Goメモ-498 (シンプルなラッチ)(CountdownLatch, CountdownEvent) - いろいろ備忘録日記
gate.go
package main type ( Gate struct { latch *CountdownLatch } ) func NewGate() *Gate { var ( latch = NewCountdownLatch(1) gate = Gate{latch} ) return &gate } func (me *Gate) Await() { if me.latch.CurrentCount() < 1 { return } me.latch.Wait() } func (me *Gate) Open() { if me.latch.CurrentCount() < 1 { return } me.latch.Signal() } func (me *Gate) Reset() { me.latch.Reset(1) }
main.go
package main import ( "context" "errors" "log" "sync" "time" ) const ( MainTimeout = 20 * time.Second ProcTimeout = 10 * time.Second ) var ( ErrMainTooSlow = errors.New("(MAIN) TOO SLOW") ErrProcTooSlow = errors.New("(PROC) TOO SLOW") ) func init() { log.SetFlags(0) } func main() { var ( rootCtx = context.Background() mainCtx, mainCxl = context.WithTimeoutCause(rootCtx, MainTimeout, ErrMainTooSlow) procCtx = run(mainCtx) err error ) defer mainCxl() select { case <-mainCtx.Done(): err = context.Cause(mainCtx) case <-procCtx.Done(): if err = context.Cause(procCtx); errors.Is(err, context.Canceled) { err = nil } } if err != nil { log.Fatal(err) } } func run(pCtx context.Context) context.Context { var ( ctx, cxl = context.WithCancelCause(pCtx) ) go func() { cxl(proc(ctx)) }() go func() { <-time.After(ProcTimeout) cxl(ErrProcTooSlow) }() return ctx } func proc(_ context.Context) error { var ( gate = NewGate() ) for range 2 { var ( wg sync.WaitGroup ) gate.Reset() // 10個のゴルーチンがゲート前に待機する for i := range 10 { wg.Add(1) go func(i int) { defer wg.Done() log.Printf("[%2d] 待機開始", i) gate.Await() log.Printf("[%2d] 待機解除", i) }(i) } // 何か準備処理などを行っているとする <-time.After(time.Second) log.Println("-------------------------------------") // ゲートを開き、待機解除したゴルーチン達が全完了するのを待つ gate.Open() wg.Wait() log.Println("*************************************") } return nil }
Taskfile.yml
# https://taskfile.dev version: '3' tasks: default: cmds: - go run .
実行
$ task [ 4] 待機開始 [ 8] 待機開始 [ 2] 待機開始 [ 3] 待機開始 [ 1] 待機開始 [ 0] 待機開始 [ 5] 待機開始 [ 6] 待機開始 [ 7] 待機開始 [ 9] 待機開始 ------------------------------------- [ 9] 待機解除 [ 4] 待機解除 [ 8] 待機解除 [ 5] 待機解除 [ 0] 待機解除 [ 1] 待機解除 [ 6] 待機解除 [ 2] 待機解除 [ 7] 待機解除 [ 3] 待機解除 ************************************* [ 9] 待機開始 [ 0] 待機開始 [ 7] 待機開始 [ 8] 待機開始 [ 4] 待機開始 [ 5] 待機開始 [ 2] 待機開始 [ 6] 待機開始 [ 1] 待機開始 [ 3] 待機開始 ------------------------------------- [ 3] 待機解除 [ 9] 待機解除 [ 5] 待機解除 [ 4] 待機解除 [ 1] 待機解除 [ 0] 待機解除 [ 7] 待機解除 [ 8] 待機解除 [ 6] 待機解除 [ 2] 待機解除 *************************************
門の前に10個のゴルーチンが集まって待機していて、門が開いたら全員一斉に駆け出して、また門が閉まって・・・って感じですね。
TDLやUSJの開園前みたいなイメージ。
参考情報
Goのおすすめ書籍
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。