golang原生的數據結構map,因爲是經過hash方式實現的,不支持併發寫入,可是在golang不少併發場景中,不可避免的須要寫入map,下面介紹兩種解決map併發寫入的實現方式:golang
首先先上代碼:數組
package main
import (
"testing"
"sync"
)
func BenchmarkTest(b *testing.B) {
var m = make(map[int]int, 10000)
var mu = &sync.Mutex{}
var c = make(chan int, 200)
var w = &sync.WaitGroup{}
w.Add(b.N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
c <- 1
go func(index int) {
mu.Lock()
m[index] = 0
mu.Unlock()
w.Done()
<- c
}(i)
}
w.Wait()
}
func BenchmarkTestBlock(b *testing.B) {
var m = make(map[int]int, 10000)
var c = make(chan int, 200)
var dataChan = make(chan int, 200)
var w = &sync.WaitGroup{}
w.Add(b.N+1)
go func() {
for i := 0; i < b.N; i++ {
m[<- dataChan] = 0
}
w.Done()
}()
b.ResetTimer()
for i := 0; i < b.N; i++ {
c<-1
go func(index int) {
dataChan <- index
w.Done()
<-c
}(i)
}
w.Wait()
}
代碼很簡潔,我就很少解釋了。數據結構
看一下執行效率 併發
能夠看到,chan的實現方式其性能並不理想,比sync.Mutex的實現方式的效率低了大約25%左右。 編輯器
chan的效率爲何不理想呢,其實緣由很簡單,下面看一下它的數據結構就一目瞭然了性能
package main import ( "fmt" ) func main() { s := "hello, world!" b := []byte(s) c := make(chan int, 1) c<-1 fmt.Println(s, b, <-c) }
咱們能夠看到channel的實現是經過互斥鎖和數組的方式實現的,並且還有一些其餘字段的同步,所以它的效率是不會比直接用互斥鎖更快的。blog
不少看上去很高端很簡潔的東西,實際上是編輯器和runtime在後面爲咱們碼農實現,固然與之相來是額外的內存和時間開銷。內存