天天看點

一道并發和鎖的golang面試題

今天面試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)

}

 主要用到了閉包,原子操作和鎖實作

---------------------

作者:自傷無色丶

來源:CSDN

原文:https://blog.csdn.net/qq_28163175/article/details/75287877

版權聲明:本文為部落客原創文章,轉載請附上博文連結!

轉載于:https://www.cnblogs.com/smallleiit/p/10891011.html