面试题答案
一键面试连接池
- 实现思路:在Go中可以使用
net/http
包结合http.Transport
结构体来实现连接池。创建一个http.Transport
实例,设置MaxIdleConns
(最大空闲连接数)、MaxIdleConnsPerHost
(每个主机的最大空闲连接数)等参数。例如:
transport := &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 10,
}
client := &http.Client{Transport: transport}
- 关键要点:合理设置连接池的参数,避免过多的连接导致资源浪费,过少的连接又影响并发性能。要根据服务器的硬件资源以及预估的并发请求量来调整参数。
缓存机制
- 实现思路:可以使用Go标准库中的
map
结合sync.RWMutex
来实现简单的缓存。例如:
type Cache struct {
data map[string]interface{}
mu sync.RWMutex
}
func (c *Cache) Get(key string) (interface{}, bool) {
c.mu.RLock()
value, exists := c.data[key]
c.mu.RUnlock()
return value, exists
}
func (c *Cache) Set(key string, value interface{}) {
c.mu.Lock()
if c.data == nil {
c.data = make(map[string]interface{})
}
c.data[key] = value
c.mu.Unlock()
}
也可以使用第三方库如groupcache
来实现分布式缓存。
2. 关键要点:要处理好缓存的过期策略,避免缓存数据长时间不更新导致数据不一致。对于高并发场景,要注意缓存读写的锁机制,防止数据竞争。
异步处理
- 实现思路:利用Go的
goroutine
进行异步处理。例如,对于一些耗时的任务,如数据库查询、文件读取等,可以将其放到goroutine
中执行,然后通过channel
来获取结果。
func asyncTask() chan string {
resultChan := make(chan string)
go func() {
// 模拟耗时操作
time.Sleep(time.Second)
resultChan <- "Task completed"
close(resultChan)
}()
return resultChan
}
- 关键要点:要合理控制
goroutine
的数量,避免创建过多的goroutine
导致资源耗尽。同时要正确处理channel
的关闭和数据接收,防止死锁。
优化路由
- 实现思路:使用高效的路由库,如
httprouter
。相比Go标准库中的http.ServeMux
,httprouter
基于树结构实现,查找路由的时间复杂度为O(log n),性能更高。
package main
import (
"github.com/julienschmidt/httprouter"
"net/http"
)
func main() {
router := httprouter.New()
router.GET("/hello/:name", func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
name := ps.ByName("name")
w.Write([]byte("Hello, " + name))
})
http.ListenAndServe(":8080", router)
}
- 关键要点:根据实际的路由结构和请求频率,合理设计路由树,避免路由匹配的性能瓶颈。
减少内存分配
- 实现思路:尽量复用内存,例如在处理HTTP请求时,对于请求体的读取,可以使用
io.Copy
并提供一个预先分配好的bufio.Reader
。
buf := make([]byte, 4096)
reader := bufio.NewReaderSize(r.Body, 4096)
_, err := io.CopyBuffer(io.Discard, reader, buf)
- 关键要点:要注意复用内存的边界条件,避免越界访问等问题。同时要根据实际场景合理选择内存复用的粒度。