sync.Poolの使い方

created byTakuya Ueda. Licensed under the Creative Commons 3.0 Attributions license.

こんにちはnasustです。
今回はsync.Poolの使い方を解説します。

sync.Pool

Go言語で高速化する為には、なるべくメモリのアロケーションを発生させない様にします。 Go言語では、オブジェクトのメモリプールの機能が用意されています。

sync.Poolはスレッドセーフなメモリプールです。sync.Poolを使用する事によって高速化することができます。

使い方は簡単で、sync.Pool構造体を生成する時のNewフィールドにオブジェクト生成の関数を指定します。必要時にNewの関数が呼ばれます。

あるスレッドで、Getメソッドを呼び、もしプールに無かったらNewの関数でオブジェクトを生成します。そしてGetでオブジェクトを取得します。もしプールにオブジェクトが在れば、そのオブジェクトを返します。使い終わったらPutメソッドでプールに戻します。

これの繰り返しでオブジェクトをリサイクルすることでメモリのアロケーションを最小限にして高速化することができます。

スレッドセーフですので、スレッド間でメモリプールする事ができます。

WEB APIなどでhttpサーバを実装した時の高速化する場合に使用すると非常に効果的です。

サンプルプログラム

package main

import (
	"fmt"
	"runtime"
	"sync"
	"time"
)

type Hoge struct {
	name  string
	value int
}

func main() {

	pool := sync.Pool{
		New: func() interface{} {
			return &Hoge{
				name:  "hoge",
				value: 0,
			}
		},
	}
	wg := &sync.WaitGroup{}

	poolFunc := func() {
		hoge := pool.Get().(*Hoge)
		if hoge.value == 0 {
			fmt.Println("New")
		} else {
			fmt.Println("Cache")
		}
		hoge.value += 1
		pool.Put(hoge)
		time.Sleep(1 * time.Microsecond)
		wg.Done()
	}

	for i := 0; i < 10; i++ {
		wg.Add(1)
		go poolFunc()
	}

	for i := 0; i < 10; i++ {
		wg.Add(1)
		go poolFunc()
	}

	wg.Wait()
	fmt.Println("End")
}

go

結果

New
New
Cache
Cache
Cache
Cache
New
Cache
Cache
Cache
Cache
Cache
Cache
Cache
Cache
Cache
Cache
Cache
Cache
Cache
END
bash
prevnext