詩と創作・思索のひろば

ドキドキギュンギュンダイアリーです!!!

Fork me on GitHub

チャンネルを使って、決まった数のリソースをgoroutine間で共有するパターン

生成が重いリソース(や重い処理の実行権)を 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
    }

リソースを取得しようとするとき、空いているものがなければブロックするので、セマフォの上位版ということになりますね。

はてなで一緒に働きませんか?