golang Slice和Map并发安全问题

golang Slice和Map并发安全问题

  1. 多个goroutine对同一个Slice进行写是不安全的。
    func main() {
    	s := []int{}
    	for i := 0; i < 10000; i++ {
    		go func(num int) {
    			s = append(s, num)
    		}(i)
    	}
    
    	time.Sleep(2 * time.Second)
    	for i, v := range s { //同时打印索引和值
    		fmt.Println(i, ":", v)
    	}
    }

打印出来切片的长度小于10000,说明有数据丢失。

通过加锁可以解决:

func main() {
	s := []int{}
	var mu sync.Mutex
	for i := 0; i < 10000; i++ {
		go func(num int) {
			mu.Lock()
			defer mu.Unlock()
			s = append(s, num)
		}(i)
	}

	time.Sleep(2 * time.Second)
	for i, v := range s { //同时打印索引和值
		fmt.Println(i, ":", v)
	}
}
  1. 多个goroutine对同一个map读是安全的
    func main() {
    	m := make(map[int]int)
    	for i := 0; i < 10000; i++ {
    		m[i] = i
    	}
    
    	count := 0
    	for i := 0; i < 10000; i++ {
    		go func(num int) {
    			if v, ok := m[num]; ok {
    				fmt.Println(v)
    			} 
    			count++
    		}(i)
    	}
    	time.Sleep(2 * time.Second)
    	fmt.Println(count)
    }
  1. 多个goroutine对同一个map写会panic
    func main() {
    	m := make(map[int]int)
    	count := 0
    	for i := 0; i < 10000; i++ {
    		go func(num int) {
    			m[num] = num
    			count++
    		}(i)
    	}
    
    	time.Sleep(2 * time.Second)
    	fmt.Println(count)
    	fmt.Println(len(m))
    }

会参数panic错误:fatal error: concurrent map writes

解决方法也是加锁。

  1. 两个goroutine分别对同一个map进行读和写会panic
    func main() {
    	m := make(map[int]int)
    	go func() {
    		for i := 0; i < 10000; i++ {
    			m[i] = i
    		}
    	}()
    
    	go func() {
    		for i := 0; i < 10000; i++ {
    			if v, ok := m[i]; ok {
    				fmt.Println(v)
    			}
    		}
    	}()
    
    	time.Sleep(2 * time.Second)
    	fmt.Println(len(m))
    }

会报错:fatal error: concurrent map read and map write

需要注意的是并不是所有情况都会报错,测试当i<1000的时候没有报错

通过加锁可以解决:

    func main() {
    	m := make(map[int]int)
    	var mu sync.Mutex
    	go func() {
    		for i := 0; i < 10000; i++ {
    			mu.Lock()
    			m[i] = i
    			fmt.Printf("写入%d\n", i)
    			mu.Unlock()
    		}
    	}()
    
    	go func() {
    		for i := 0; i < 10000; i++ {
    			mu.Lock()
    			if v, ok := m[i]; ok {
    				fmt.Println(v)
    			}
    			mu.Unlock()
    		}
    	}()
    
    	time.Sleep(2 * time.Second)
    	fmt.Println(len(m))
    }
    ```



你可能感兴趣的:(golang)