一道併發和鎖的golang面試題
阿新 • • 發佈:2019-01-26
今天面試golang碰到了一道考併發和鎖的題目,沒有完成,所以把它記錄下來,僅為以後複習。
場景:在一個高併發的web伺服器中,要限制IP的頻繁訪問。現模擬100個IP同時併發訪問伺服器,每個IP要重複訪問1000次。每個IP三分鐘之內只能訪問一次。修改以下程式碼完成該過程,要求能成功輸出 success:100
package main import ( "fmt" "time" ) type Ban struct { visitIPs map[string]time.Time } func NewBan() *Ban { return &Ban{visitIPs: make(map[string]time.Time)} } func (o *Ban) visit(ip string) bool { if _, ok := o.visitIPs[ip]; ok { return true } o.visitIPs[ip] = time.Now() return false } func main() { success := 0 ban := NewBan() for i := 0; i < 1000; i++ { 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) }
以上程式碼有一些坑。當時也是沒有做出來,回來請教一位大佬,得以解決。
package main import ( "fmt" "sync" "sync/atomic" "time" ) type Ban struct { visitIPs map[string]struct{} } func NewBan() *Ban { return &Ban{visitIPs: make(map[string]struct{})} } //判斷IP是否存在 func (o *Ban) visit(ip string) bool { mapMutex.Lock() defer mapMutex.Unlock() if _, ok := o.visitIPs[ip]; ok { return true } o.visitIPs[ip] = struct{}{} go o.invalidAfter3Min(ip) return false } // 3分鐘後ip失效, 從map中移除. 因此ip再次訪問時便可正常訪問 func (o *Ban) invalidAfter3Min(ip string) { time.Sleep(time.Minute * 3) mapMutex.Lock() visitIPs := o.visitIPs delete(visitIPs, ip) o.visitIPs = visitIPs mapMutex.Unlock() } var mapMutex *sync.Mutex // mutex to avoid concurrent map writes func main() { mapMutex = new(sync.Mutex) var success int64 ban := NewBan() wg := new(sync.WaitGroup) for i := 0; i < 1000; i++ { for j := 0; j < 100; j++ { wg.Add(1) ipEnd := j go func() { defer wg.Done() ip := fmt.Sprintf("192.168.1.%d", ipEnd) if !ban.visit(ip) { atomic.AddInt64(&success, 1) } }() } } wg.Wait() fmt.Println("success:", success) }
主要用到了閉包,原子操作和鎖實現