MST

星途 面试题库

面试题:Go闭包在并发场景下的复杂应用

在一个高并发的Go程序中,需要利用闭包实现一个安全的资源池。资源池中的资源是有限的,多个协程会竞争获取资源,使用完毕后归还资源。请设计并实现这样一个基于闭包的资源池结构,并确保在高并发场景下资源的正确分配与回收,同时要考虑性能优化,尽量减少锁的使用。请详细说明设计思路和代码实现。
31.2万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 资源池结构体:定义一个结构体来表示资源池,包含资源数量、可用资源通道以及一个标志位用于标记资源池是否关闭。
  2. 获取资源函数:通过闭包实现获取资源的逻辑,从可用资源通道中获取资源,如果通道为空则等待直到有资源可用或者资源池关闭。
  3. 归还资源函数:同样通过闭包实现归还资源的逻辑,将资源放回可用资源通道。
  4. 减少锁使用:利用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函数中演示了如何使用这个资源池。