Golang面试经典案例分享

  1. 请修改以下代码,使其满足所示题目要求

    场景:在一个高并发的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)
    }
    
    此代码为并发的写map集合的经典案例,其中有几个问题
  • - 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)
    }
    
  1. map集合底层实现原理
  • - 数据结构: 红黑树
    
  • - Hash函数 + Hash集合
    
  1. context包的作用
  • - 协调多个goroutine
    
  • - 传递上下文信息
    
  • - 传递请求范围的值
    
  • - 管理请求的生命周期
    
posted @ 2024-08-19 20:41  yuese00  阅读(43)  评论(0编辑  收藏  举报