生成が重いリソース(や重い処理の実行権)を goroutine 間で共有し使いまわすようなパターンです。よく知られていて名前がついていそうだけど、ぐぐっても分からなかったので書いておく。
コネクションプールに近い感じで、最初にリソースを生成したあと、それらを大事に取り回します。リソースが空いてなかったら goroutine は待つことにする。sync.Pool は「プールにあったら使うけど、なかったら新しく作る」くらいの感じなので、ちょっとスタンスが違う。
チャンネルによる実装は簡単で、以下のエントリにも書いたセマフォを応用すればよい。
ざっくりと書いてみた例がこちら: https://play.golang.org/p/QWAXsA_89Y
チャンネルによるセマフォの実装は、「バッファありチャンネルに何か(struct{}
)を挿入できた goroutine が実行の権利を持つ」というものでしたが、今回は「バッファありチャンネルからリソースを取得できた goroutine がリソースの権利を持つ」というふうになっています。
最初にリソースのプール(チャンネル)を作り:
pool := make(chan *worker, 5) for i := 0; i < 5; i++ { pool <- &worker{i} }
各 gorountine では、リソースをプールから取得。リソースを使い終わったらプールに戻します。プールに戻すまではリソースを占有できていることが保証されています。
case w := <-pool:
w.work()
pool <- w
}
リソースを取得しようとするとき、空いているものがなければブロックするので、セマフォの上位版ということになりますね。