面试题答案
一键面试设计思路
- 资源池结构体:定义一个结构体来表示资源池,包含资源数量、可用资源通道以及一个标志位用于标记资源池是否关闭。
- 获取资源函数:通过闭包实现获取资源的逻辑,从可用资源通道中获取资源,如果通道为空则等待直到有资源可用或者资源池关闭。
- 归还资源函数:同样通过闭包实现归还资源的逻辑,将资源放回可用资源通道。
- 减少锁使用:利用Go语言的通道特性来实现资源的同步访问,避免在每次获取和归还资源时都使用锁,从而提高性能。
代码实现
package main
import (
"fmt"
"sync"
)
// Resource 表示资源
type Resource struct {
ID int
}
// ResourcePool 资源池结构体
type ResourcePool struct {
resources chan *Resource
closed bool
wg sync.WaitGroup
}
// NewResourcePool 创建一个新的资源池
func NewResourcePool(size int) *ResourcePool {
pool := &ResourcePool{
resources: make(chan *Resource, size),
closed: false,
}
for i := 0; i < size; i++ {
pool.resources <- &Resource{ID: i}
}
return pool
}
// Acquire 获取资源
func (p *ResourcePool) Acquire() *Resource {
var res *Resource
select {
case res = <-p.resources:
case <-p.Closed():
res = nil
}
return res
}
// Release 归还资源
func (p *ResourcePool) Release(res *Resource) {
if p.closed {
return
}
select {
case p.resources <- res:
default:
// 如果资源池已满,可能是资源池关闭后仍有归还操作,这里可以选择忽略或者记录日志
}
}
// Close 关闭资源池
func (p *ResourcePool) Close() {
p.closed = true
close(p.resources)
p.wg.Wait()
}
// Closed 判断资源池是否关闭
func (p *ResourcePool) Closed() <-chan struct{} {
ch := make(chan struct{})
go func() {
if p.closed {
close(ch)
}
}()
return ch
}
func main() {
pool := NewResourcePool(5)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
res := pool.Acquire()
if res != nil {
fmt.Printf("协程 %d 获取到资源 %d\n", id, res.ID)
// 使用资源
pool.Release(res)
fmt.Printf("协程 %d 归还资源 %d\n", id, res.ID)
} else {
fmt.Printf("协程 %d 无法获取资源,资源池已关闭\n", id)
}
}(i)
}
pool.Close()
wg.Wait()
}
上述代码实现了一个基于闭包的资源池,在高并发场景下可以安全地分配和回收资源,并且通过通道特性减少了锁的使用,提高了性能。在main
函数中演示了如何使用这个资源池。