Go:rwmutex-and-sync.map

map with RWMutex和之间进行比较sync.Map

读或写测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package main

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

type rwMap struct {
data map[int]int
m sync.RWMutex
}

var (
rwm = rwMap{data: make(map[int]int)}
end = int(1e7)
syncM sync.Map
)

func main() {

fmt.Println("write test")
// rw map
start := time.Now()
for i := 0; i < end; i++ {
rwm.m.Lock()
rwm.data[i] = i
rwm.m.Unlock()
}
fmt.Printf("rw map used %v\n", time.Since(start))

// sync Map
start = time.Now()
for i := 0; i < end; i++ {
syncM.Store(i, i)
}
fmt.Printf("sync map used %v\n\n", time.Since(start))

fmt.Println("read test")
// rw map
start = time.Now()
for i := 0; i < end; i++ {
rwm.m.RLock()
_ = rwm.data[i]
rwm.m.RUnlock()
}
fmt.Printf("rw map used %v\n", time.Since(start))

// sync Map
start = time.Now()
for i := 0; i < end; i++ {
_, _ = syncM.Load(i)
}
fmt.Printf("sync map used %v\n\n", time.Since(start))

}

结果

1
2
3
4
5
6
7
8
9
➜  comparation go run main.go
write test
rw map used 3.012520671s
sync map used 10.648790268s

read test
rw map used 1.124830897s
sync map used 2.328729454s
➜ comparation

Cocurrency读写测试

用rw-mutex映射

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package main

import (
"fmt"
"sync"
"sync/atomic"
"time"
)

type rwMap struct {
data map[int]int
m sync.RWMutex
}

var (
rwm = rwMap{data: make(map[int]int)}
end = int(1e7)
// syncM sync.Map
readTimes uint64
)

func init() {
for i := 0; i < end; i++ {
rwm.data[i] = i
}
}

func read() {
for {
for i := 0; i < end; i++ {
rwm.m.RLock()
atomic.AddUint64(&readTimes, 1)
if rwm.data[i] != i {
panic("!")
}
rwm.m.RUnlock()
}
}
}

func write() {
n := time.Now().Nanosecond() % 1000
rwm.m.Lock()
rwm.data[n] = n
rwm.m.Unlock()
}

func main() {
start := time.Now()
// 10 gouroutine to read data
for i := 0; i < 10; i++ {
go read()
}

time.Sleep(time.Second)
// write 100 times
for i := 0; i < 100; i++ {
write()
}

fmt.Printf("read %d, used %v\n", readTimes, time.Since(start.Add(-time.Second)))
}

结果

1
2
3
➜  comparation go run main.go
read 13163604, used 2.019429333s
➜ comparation

sync.Map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package main

import (
"fmt"
"sync"
"sync/atomic"
"time"
)

type rwMap struct {
data map[int]int
m sync.RWMutex
}

var (
rwm = rwMap{data: make(map[int]int)}
end = int(1e7)

syncM sync.Map
readTimes uint64
)

func init() {
for i := 0; i < end; i++ {
rwm.data[i] = i
}
}

func read() {
for {
for i := 0; i < end; i++ {
atomic.AddUint64(&readTimes, 1)
syncM.Load(i)
}
}
}

func write() {
n := time.Now().UnixNano() % 1000
syncM.Store(n, n)
}

func main() {
start := time.Now()
// 10 gouroutine to read data
for i := 0; i < 10; i++ {
go read()
}

time.Sleep(time.Second)
// write 100 times
for i := 0; i < 100; i++ {
write()
}

fmt.Printf("read %d, used %v\n", readTimes, time.Since(start.Add(-time.Second)))
}

结果

1
2
3
➜  comparation go run main.go
read 95246260, used 2.30790947s
➜ comparation

sync.Map并发读取能力比使用rw互斥锁的map要好得多

结论

sync.Map 适用于具有高并发读取和较少写入操作的场景。但是在单个goroutine中读取或写入map的情况下,最好使用带有rw-mutex的map。