网络编程
位置:首页>> 网络编程>> Go语言>> golang使用map支持高并发的方法(1000万次操作14ms)

golang使用map支持高并发的方法(1000万次操作14ms)

作者:飞鸟真人  发布时间:2024-05-13 10:41:33 

标签:golang,map,并发

语言原生的map存在2个问题:

1)不是线程安全的;

2)数据量大时候需要尽量避免使用string等,GC压力很大;

有人使用泛型实现了相关的cocurent-map,(https://github.com/orcaman/concurrent-map)但是关于键值部分仍然默认使用了string,为了提高效率,这里对其做了一些修改,让键值也可以自定义类型:https://github.com/robinfoxnan/go_concurrent_map

基本使用方法:

// Create a new map.
m := cache.NewConcurrentMap[uint64, string]()

// Sets item within map, sets "bar" under key "foo"
m.Set(199010212, "bar")

// Retrieve item from map.
bar, ok := m.Get(199010212)
fmt.Println(bar, ok)

// Removes item under key "foo"
m.Remove(199010212)

为了实现计数器等,需要在加锁期间更新,需要使用回调函数:

// 计数器
type BaseCounter struct {
Count     uint64
CountLast uint64
}

var MapOfAppUserCount ConcurrentMap[uint64, *AppUserCounter]

func InitMaps() {
MapOfAppVistedCount = NewConcurrentMap[uint64, *BaseCounter]()
}

// 没有值,则设置;如果有,则更新; 新增的部分通过新的值传递过来!
func appAddCallBack(exist bool, valueInMap *BaseCounter, newValue *BaseCounter) *BaseCounter {
if exist == false {
return newValue
} else {
valueInMap.Count += newValue.Count
return valueInMap
}
}

// 对应用计数器加i
func AppAddBy(key uint64, i uint64) uint64 {
c := BaseCounter{i, i}
res := MapOfAppVistedCount.Upsert(key, &c, appAddCallBack)
if res != nil {
return res.Count
}
return 0
}

计数器的使用如下:

cache.InitMaps()
cache.AppAddBy(i, 1)

性能:

1)单线程初始化1~1000w的计数器,2412  ms

2)分给100个协程,14ms

测试代码如下:

func testSingle() {
cache.InitMaps()
timeUnixNano1 := time.Now().UnixMilli()
// 100万次更新
for i := uint64(0); i < 10000000; i++ {
cache.AppAddBy(i, 1)
}
timeUnixNano2 := time.Now().UnixMilli()
delta := timeUnixNano2 - timeUnixNano1
fmt.Println("cost: ", delta, " ms")

count := cache.AppAddBy(1, 1)
fmt.Println(count)
count = cache.AppAddBy(1, 2)
fmt.Println(count)
count = cache.AppAddBy(1, 3)
fmt.Println(count)
}

var N int = 10000000

func doInsert(n int, index int, g *sync.WaitGroup) {
m := N / n
start := index * m

//fmt.Println("thread ", index, "from ", start)
for i := uint64(start); i < uint64(m); i++ {
cache.AppAddBy(i, 1)
}
if g != nil {
g.Done()
}
}

func testMulti() {
cache.InitMaps()

group := sync.WaitGroup{}
n := 100
group.Add(n)
timeUnixNano1 := time.Now().UnixMilli()
for i := 0; i < n; i++ {
go doInsert(n, i, &group)
}
group.Wait()
timeUnixNano2 := time.Now().UnixMilli()
delta := timeUnixNano2 - timeUnixNano1
fmt.Println("cost: ", delta, " ms")

}

来源:https://blog.csdn.net/robinfoxnan/article/details/127842693

0
投稿

猜你喜欢

手机版 网络编程 asp之家 www.aspxhome.com