こんにちは。KOUKIです。
とあるWeb系企業で、Go言語エンジニアをしています。
学習のメモ代わりに記事を書いています。
今日は、syncパッケージのPoolを紹介したいと思います。
sync.Poolは、以下の構造体になっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
type Pool struct { noCopy noCopy local unsafe.Pointer // local fixed-size per-P pool, actual type is [P]poolLocal localSize uintptr // size of the local array victim unsafe.Pointer // local from previous cycle victimSize uintptr // size of victims array // New optionally specifies a function to generate // a value when Get would otherwise return nil. // It may not be changed concurrently with calls to Get. New func() any } |
Poolという名のとおり、何らかのものを貯めておけ、必要なタイミングになったらそれを取り出すことができます。
実際にコードで確認していきましょう!
<目次>
sync.Poolなし版
最初にsync.Poolなし版のコードを紹介します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package main import ( "bytes" "io" "os" "time" ) func log(w io.Writer, val string) { var b bytes.Buffer b.WriteString(time.Now().Format("15:04:05")) b.WriteString(" : ") b.WriteString(val) b.WriteString("\n") w.Write(b.Bytes()) } func main() { log(os.Stdout, "debug-string1") log(os.Stdout, "debug-string2") } |
log関数内で、「bytes.Buffer」を作成し、そこに出力したい文字を貯めて、最後に標準出力に出力する簡単なプログラムです。出力結果は以下です。
1 2 3 |
$ go run main.go 04:39:10 : debug-string1 04:39:10 : debug-string2 |
このコードは、log関数を呼び出すごとに「bytes.Buffer」を作成しているので、少し効率が悪いです。これをsync.Poolを使って改善してみましょう。
sync.Poolあり版
先ほどのコードをsync.Poolで書き換えたものがこちらになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package main import ( "bytes" "fmt" "io" "os" "sync" "time" ) var bufPool = sync.Pool{ New: func() any { fmt.Println("allocating new bytes.Buffer") return new(bytes.Buffer) }, } func log(w io.Writer, val string) { // var b bytes.Buffer b := bufPool.Get().(*bytes.Buffer) b.Reset() b.WriteString(time.Now().Format("15:04:05")) b.WriteString(" : ") b.WriteString(val) b.WriteString("\n") w.Write(b.Bytes()) bufPool.Put(b) } func main() { log(os.Stdout, "debug-string1") log(os.Stdout, "debug-string2") } |
sync.PoolのNewプロパティには無名関数をセットします。ここでは、「bytes.Buffer」を返却する無名関数をセットしており、log関数内でキャスト(bufPool.Get().(*bytes.Buffer))して使っています。
Resetメソッドは、Buffer内を空にします。
最後に、buffer(変数b)をbufPoolのPutメソッドで保存してあげれば完成、というわけです。
出力結果は先ほどと変わりませんが、なかなか効率のいいプログラムになったと思います。
1 2 3 4 |
$ go run main.go allocating new bytes.Buffer 04:59:45 : debug-string1 04:59:45 : debug-string2 |
おわりに
sync.Poolは結構便利だと思いますが、それなりにプログラミングスキルが求められるかもしれないですね。
意外な落とし穴でバグを生まないように、慎重に実装していただけたらと^^;
それでは、また!
Go言語まとめ

コメントを残す
コメントを投稿するにはログインしてください。