注:
多くは一時的オブジェクトのための高速、良い実装ですsync.Pool
を使用することをお勧めします。ただし、sync.Pool
はプールされたオブジェクトが保持されることを保証しません。そのドキュメントからの引用:
プールに格納された任意の項目が通知ことなく、いつでも自動的に除去することができます。このときプールに唯一の参照が保持されていれば、アイテムの割り当てが解除される可能性があります。
あなたは(あなたのケースによっては、より配分につながる可能性がある)Pool
であなたのオブジェクトがガベージコレクションを取得したくない場合は、チャネルのバッファ内の値がでないように、以下に提示するソリューションは、優れていますガベージコレクション。あなたのオブジェクトが実際に大きすぎてメモリプールが正当化されない場合、プールチャネルのオーバーヘッドは償却されます。
最も単純なメモリプール "実装"は、バッファされたチャネルです。
大きなオブジェクトのメモリプールが必要な場合を考えてみましょう。そのような高価なオブジェクトの値へのポインタを保持するバッファされたチャネルを作成し、必要なときにはプール(チャネル)から1つを受け取ります。あなたがそれを使用し終わったら、それをプールに戻してください(チャンネルを送ってください)。誤ってオブジェクトを失うのを防ぐには(例えばパニックの場合)、それらを戻す際にdefer
のステートメントを使用します。
のが私たちの大きなオブジェクトの種類としてこれを使用してみましょう:プールの作成
type BigObject struct {
Id int
Something string
}
は次のとおりです。
pool := make(chan *BigObject, 10)
プールのサイズは、単にチャネルのバッファのサイズです。
高価なオブジェクトのポインタを持つプール(これはオプションで、最後にノートを参照してください)充填:多くのゴルーチンでプールを使用して
for i := 0; i < cap(pool); i++ {
bo := &BigObject{Id: i}
pool <- bo
}
を:
wg := sync.WaitGroup{}
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
bo := <-pool
defer func() { pool <- bo }()
fmt.Println("Using", bo.Id)
fmt.Println("Releasing", bo.Id)
}()
}
wg.Wait()
はGo Playground上でそれを試してみてください。
「プールされた」オブジェクトがすべて使用されている場合、この実装はブロックされることに注意してください。
var bo *BigObject
select {
case bo = <-pool: // Try to get one from the pool
default: // All in use, create a new, temporary:
bo = &BigObject{Id:-1}
}
そして、この場合には、あなたがプールに戻ってそれを配置する必要はありません:あなたはこれをしたくない場合は、すべてが使用中である場合は、新しいオブジェクトを作成する強制的にselect
を使用することができます。それとも、部屋がプールにあるかどうselect
で再び、ブロックせずに、プールにすべてのバック入れしようとすることもできます:
select {
case pool <- bo: // Try to put back into the pool
default: // Pool is full, will be garbage collected
}
注:以前はオプションでプールを充填
。 select
を使用してプールから値を取得/プールしようとすると、プールは最初は空になることがあります。
リクエスト間で情報が漏洩していないことを確認する必要があります。他の要求に設定されている共有オブジェクトでフィールドと値を使用しないようにしてください。
[sync.Pool'](https://golang.org/pkg/sync/#Pool)がstdlibにあります。それ以外に、 "フリーリスト"を実装することは、Goに固有のものではないテクニックです。 – JimB