| by suyi | No comments

Go:rwmutex-and-sync.map

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

读或写测试

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))

}

结果

➜  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映射

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)))
}

结果

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

sync.Map

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)))
}

结果

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

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

结论

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

发表评论