Implementing manual object pooling can be useful in scenarios where the built-in sync.Pool
doesn't fit the requirements, such as when you need more control over the pooling behavior or when you need to manage resources other than memory. Here's a simple example of how you can implement manual object pooling in Go:
gopackage main
import (
"fmt"
"sync"
)
// Resource represents the object that will be pooled.
type Resource struct {
ID int
// Add other fields as needed
}
// Pool represents the manual object pool.
type Pool struct {
mu sync.Mutex
resources []*Resource
maxSize int
allocCount int
}
// NewPool creates a new instance of Pool with the specified maxSize.
func NewPool(maxSize int) *Pool {
return &Pool{
resources: make([]*Resource, 0, maxSize),
maxSize: maxSize,
}
}
// Acquire retrieves a resource from the pool or creates a new one if the pool is empty.
func (p *Pool) Acquire() *Resource {
p.mu.Lock()
defer p.mu.Unlock()
if len(p.resources) == 0 {
if p.allocCount < p.maxSize {
p.allocCount++
return &Resource{ID: p.allocCount}
}
return nil // Pool is at max capacity
}
r := p.resources[len(p.resources)-1]
p.resources = p.resources[:len(p.resources)-1]
return r
}
// Release returns a resource to the pool.
func (p *Pool) Release(r *Resource) {
p.mu.Lock()
defer p.mu.Unlock()
p.resources = append(p.resources, r)
}
func main() {
pool := NewPool(3)
// Acquire resources from the pool
for i := 0; i < 5; i++ {
resource := pool.Acquire()
if resource == nil {
fmt.Println("Pool is full, cannot acquire more resources")
break
}
fmt.Printf("Acquired resource: %d\n", resource.ID)
}
// Release resources back to the pool
for i := 1; i <= 3; i++ {
resource := &Resource{ID: i}
pool.Release(resource)
fmt.Printf("Released resource: %d\n", resource.ID)
}
}
In this example:
Resource
struct that represents the objects we want to pool.Pool
struct manages the resources and provides methods to acquire and release them.Acquire
method locks the pool mutex to ensure thread safety during resource acquisition.Release
method releases a resource back to the pool.main
function, we demonstrate acquiring and releasing resources from the pool.This is a basic example of manual object pooling. Depending on your specific use case, you may need to extend this implementation to suit your requirements, such as adding resource expiration, cleaning up resources, or managing more complex resource types.