【golang】优雅且安全的并发写slice或map

it2022-05-05  169

并发写 slice和map是不安全的

【golang面试准备】验证map&slice并发不安全

怎么能高并发写入?

slice&map并发不安全,都是在写的时候发生的,那么就要保证同一时间只有一个gorutine来写这个slice或者map。

有两种方式实现:

加锁方式:n个goroutine都有可能执行写入操作,保证同一时间只能有一个在执行写操作。 加锁操作简单,适用于性能要求低和逻辑不复杂的场景。 package main import ( "fmt" "sync" ) func main() { slc := []int{} n := 10000 var wg sync.WaitGroup var lock sync.Mutex wg.Add(n) for i := 0; i < n; i++ { go func(a int) { lock.Lock() slc = append(slc, a) lock.Unlock() wg.Done() }(i) } wg.Wait() fmt.Println("done len:", len(slc)) } Active Object方式:只有1个goroutine在执行写操作。避免多个goroutine竞争锁。 适合业务场景复杂,性能要求高的场景。 package main import ( "fmt" "sync" ) // active object对象 type Service struct { channel chan int `desc:"即将加入到数据slice的数据"` data []int `desc:"数据slice"` } // 新建一个size大小缓存的active object对象 func NewService(size int, done func()) *Service { s := &Service{ channel: make(chan int, size), data: make([]int, 0), } go func() { s.schedule() done() }() return s } // 把管道中的数据append到slice中 func (s *Service) schedule() { for v := range s.channel { s.data = append(s.data, v) } } // 增加一个值 func (s *Service) Add(v int) { s.channel <- v } // 管道使用完关闭 func (s *Service) Close() { close(s.channel) } // 返回slice func (s *Service) Slice() []int { return s.data } func main() { // 1. 新建一个active object, 并增加结束信号 c := make(chan struct{}) s := NewService(100, func() { c <- struct{}{} }) // 2. 起n个goroutine不断执行增加操作 n := 10000 var wg sync.WaitGroup wg.Add(n) for i := 0; i < n; i++ { go func(a int) { s.Add(a) wg.Done() }(i) } wg.Wait() s.Close() <-c // 3. 校验所有结果是否都被添加上 fmt.Println("done len:", len(s.Slice())) }

最新回复(0)