机器及环境:
代码编辑器:Visual Studio Code
读写锁:sync.RWMutex
互斥锁:sync.Mutex{}
Go版本:go version go1.16 windows/amd64
测试:
一共7个协程,6个协程用于读map中的数据,1个协程用于写入map数据,计算所有协程完成工作后的总时间,列出以下表格,
以下所有时间单位为:秒
循环次数(每个协程) | 读写map全加Lock锁[RWMutex] | 读map加RLock 锁,写map加Lock锁[RWMutex] | 读写map加Lock锁[Mutex] |
---|---|---|---|
1千 | 0.0029211 | 0.0019989 | 0.0030007 |
1万 | 0.0132632 | 0.0110304 | 0.0072183 |
10万 | 0.1046344 | 0.1441308 | 0.0703651 |
100万 | 0.9638649 | 1.0364884 | 0.7389124 |
500万 | 4.7609394 | 4.4947625 | 3.6153809 |
1000万 | 9.4329156 | 9.4223508 | 7.5078914 |
2000万 | 20.023867 | 18.038904 | 15.124100 |
3000万 | 29.065017 | 26.220366 | 21.868782 |
1亿 | 95.763412 | 95.097358 | 69.762031 |
结论:
- 互斥锁的效率比读写锁要好
- 在读写锁中,读map加Rlock,写map加Lock锁,表现会更好一些
以下是测试代码:
package cmd
import (
"fmt"
"sync"
"time"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(bufferCmd)
}
const Times = 1_0000_0000
var bufferCmd = &cobra.Command{
Use: "buffert",
Run: func(cmd *cobra.Command, args []string) {
dd := NewDianDian()
w := sync.WaitGroup{}
start := time.Now()
w.Add(7)
for i := 0; i < 6; i++ {
go R(dd, &w, i)
}
go W(dd, &w)
w.Wait()
fmt.Printf("total: %v\n", time.Now().Sub(start).Seconds())
},
}
type diandian struct {
M map[string]int
RWLock sync.RWMutex
Lock sync.Mutex
}
func NewDianDian() *diandian {
dd := &diandian{}
dd.M = map[string]int{}
dd.Lock = sync.Mutex{}
dd.RWLock = sync.RWMutex{}
return dd
}
func (dd *diandian) Write(name string, value int) {
// sync.RWMutex{}
dd.RWLock.Lock()
defer dd.RWLock.Unlock()
// sync.Mutex{}
// dd.Lock.Lock()
// defer dd.Lock.Unlock()
dd.M[name] = value
}
func (dd *diandian) Read(name string) int {
// sync.RWMutex{}
// dd.RWLock.RLock()
// defer dd.RWLock.RUnlock()
dd.RWLock.Lock()
defer dd.RWLock.Unlock()
// sync.Mutex{}
// dd.Lock.Lock()
// defer dd.Lock.Unlock()
if value, ok := dd.M[name]; ok {
return value
}
return 0
}
func R(dd *diandian, w *sync.WaitGroup, n int) {
defer w.Done()
start := time.Now()
for i := 0; i <= Times; i++ {
dd.Read("start")
}
fmt.Printf("time[R-%d]: %v\n", n, time.Now().Sub(start).Seconds())
}
func W(dd *diandian, w *sync.WaitGroup) {
defer w.Done()
start := time.Now()
for i := 0; i <= Times; i++ {
dd.Write("start", 1)
}
fmt.Printf("time[W]: %v\n", time.Now().Sub(start).Seconds())
}