面试题答案
一键面试package main
import (
"fmt"
"sync"
)
// 定义资源类型
type Resource struct {
// 资源的具体数据
Data string
}
// 定义资源池
type ResourcePool struct {
resources chan *Resource
max int
mu sync.Mutex
inUse map[*Resource]bool
}
// 创建资源池
func NewResourcePool(max int) *ResourcePool {
return &ResourcePool{
resources: make(chan *Resource, max),
max: max,
inUse: make(map[*Resource]bool),
}
}
// 从资源池获取资源
func (rp *ResourcePool) Get() (*Resource, error) {
rp.mu.Lock()
if len(rp.resources) == 0 && len(rp.inUse) >= rp.max {
rp.mu.Unlock()
return nil, fmt.Errorf("资源池已耗尽")
}
rp.mu.Unlock()
select {
case res := <-rp.resources:
rp.mu.Lock()
rp.inUse[res] = true
rp.mu.Unlock()
return res, nil
default:
// 创建新资源
newRes := &Resource{Data: "新资源"}
rp.mu.Lock()
rp.inUse[newRes] = true
rp.mu.Unlock()
return newRes, nil
}
}
// 归还资源到资源池
func (rp *ResourcePool) Put(res *Resource) {
rp.mu.Lock()
if _, ok := rp.inUse[res]; ok {
delete(rp.inUse, res)
select {
case rp.resources <- res:
default:
// 资源池已满,直接丢弃
}
}
rp.mu.Unlock()
}
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, err := pool.Get()
if err != nil {
fmt.Printf("goroutine %d 获取资源失败: %v\n", id, err)
return
}
defer pool.Put(res)
fmt.Printf("goroutine %d 使用资源: %v\n", id, res.Data)
}(i)
}
wg.Wait()
}
上述代码实现了一个资源池:
- Resource 结构体:定义了资源的类型。
- ResourcePool 结构体:包含资源通道
resources
、最大资源数max
、互斥锁mu
和正在使用的资源映射inUse
。 - NewResourcePool 函数:用于创建资源池实例。
- Get 方法:从资源池获取资源,如果资源池为空且使用中的资源达到最大数,则返回错误。否则从通道获取资源或创建新资源。
- Put 方法:将资源归还到资源池,如果资源正在使用,则从
inUse
中删除并尝试放入通道,如果通道已满则丢弃。 - main 函数:演示了如何使用资源池,启动多个 goroutine 并发获取和归还资源。