Golang面试经典案例分享
-
请修改以下代码,使其满足所示题目要求
场景:在一个高并发的web服务器中,要限制IP的频繁访问。
以下代码模拟100个IP同时并发访问服务器,每个IP会重复访问1000次。限制每个IP三分钟之内只能访问一次。
修改以下代码完成该过程,要求能成功输出 success:100点击查看代码
package main import ( "fmt" "sync" "time" ) type Ban struct { visitIPs map[string]time.Time } func NewBan() *Ban { return &Ban{visitIPs: make(map[string]time.Time)} } // true 表示三分钟内访问过 限制访问,false表示三分钟内没有访问过 func (o *Ban) visit(ip string) bool { if _, ok := o.visitIPs[ip]; ok { return true } o.visitIPs[ip] = time.Now() // 模拟耗时操作 time.Sleep(time.Millisecond * 200) return false } func main() { var wg sync.WaitGroup success := 0 ban := NewBan() // 每个 i 表示一次访问 for i := 0; i < 1000; i++ { // 每个 j 表示一个单独的IP for j := 0; j < 100; j++ { go func() { ip := fmt.Sprintf("192.168.1.%d", j) if !ban.visit(ip) { success++ } }() } } fmt.Println("success:", success) }
-
- golang主线程是不会等待协程执行完毕的,可以使用sync.WaitGroup包阻塞主线程
-
- 多协程并发写,读map是不安全的,需要加锁
-
- 不使用闭包
这是修改之后代码
点击查看代码
package main import ( "fmt" "sync" "time" ) var mutex sync.Mutex type Ban struct { visitIPs map[string]time.Time } func NewBan() *Ban { return &Ban{visitIPs: make(map[string]time.Time)} } // true 表示三分钟内访问过 限制访问,false表示三分钟内没有访问过 func (o *Ban) visit(ip string) bool { mutex.Lock() defer mutex.Unlock() if _, ok := o.visitIPs[ip]; ok { return true } o.visitIPs[ip] = time.Now() // 模拟耗时操作 time.Sleep(time.Millisecond * 200) return false } func main() { var wg sync.WaitGroup success := 0 ban := NewBan() // 每个 i 表示一次访问 for i := 0; i < 1000; i++ { // 每个 j 表示一个单独的IP for j := 0; j < 100; j++ { wg.Add(1) go func(j int) { defer wg.Done() ip := fmt.Sprintf("192.168.1.%d", j) if !ban.visit(ip) { success++ } }(j) } } wg.Wait() fmt.Println("success:", success) }
- map集合底层实现原理
-
- 数据结构: 红黑树
-
- Hash函数 + Hash集合
- context包的作用
-
- 协调多个goroutine
-
- 传递上下文信息
-
- 传递请求范围的值
-
- 管理请求的生命周期