golang map并发性

假如我们没有用协程通道或者加锁的方式,直接并发使用map,会出现线性不安全

例如:

package main

import (
	"time"
	"fmt"
)

var tMap map[int]int

func main() {
	tMap = make(map[int]int)
	for i := 0; i < 10000; i++ {
		go putMap(i)
	}
	time.Sleep(1e10)
	fmt.Println("--------------map = ", len(tMap))
}

func putMap(i int)  {
	tMap[i] = i
}

  

报错:

解决方法:

使用锁之后就不会有问题:

package main

import (
	"time"
	"fmt"
	"sync"
)

var tMap map[int]int
var mutex sync.Mutex

func main() {
	tMap = make(map[int]int)
	for i := 0; i < 10000; i++ {
		go putMap(i)
	}
	time.Sleep(1e10)
	fmt.Println("--------------map = ", len(tMap))
}

func putMap(i int)  {
	mutex.Lock()
	tMap[i] = i
	mutex.Unlock()
}

  

又或者是利用协程通道,来保证线程安全

package main

import (
	"time"
	"fmt"
)

var tMap map[int]int

func main() {
	tMap = make(map[int]int)
	data := make(chan int)
	go goroutine(data)
	for i := 0; i < 10000; i++ {
		go putMap(data, i)
	}
	time.Sleep(1e10)
	fmt.Println("--------------map = ", len(tMap))
}

func putMap(data chan int, i int)  {
	data <- i
}

func goroutine(data chan int)  {
	for {
		i := <- data
		tMap[i] = i
	}
}

  

Go的哲学之一就是:不要通过共享内存来通信,而要通过通信来共享内存,前者就是传统的加锁,后者就是Channel。

反正涉及到并发安全性的数据结构,尽量使用协程通道:发送一个数据到Channel 和 从Channel接收一个数据 都是 原子性的。

可以认为加锁的map就是erlang里面的ets,而使用协程通道就是erlang里面的进程里的数据结构

猜你喜欢

转载自www.cnblogs.com/huangliang-hb/p/10049547.html