博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
优化 Go 中的 map 并发存取
阅读量:7009 次
发布时间:2019-06-28

本文共 1239 字,大约阅读时间需要 4 分钟。

地址:

Catena (时序存储引擎)中有一个函数的实现备受争议,它从 map 中根据指定的 name 获取一个 metricSource。每一次插入操作都会至少调用一次这个函数,现实场景中该函数调用更是频繁,并且是跨多个协程的,因此我们必须要考虑同步。

该函数从 map[string]*metricSource 中根据指定的 name 获取一个指向 metricSource 的指针,如果获取不到则创建一个并返回。其中要注意的关键点是我们只会对这个 map 进行插入操作。

var source *memorySourcevar present boolp.lock.Lock() // lock the mutexdefer p.lock.Unlock() // unlock the mutex at the endif source, present = p.sources[name]; !present {	// The source wasn't found, so we'll create it.	source = &memorySource{		name: name,		metrics: map[string]*memoryMetric{},	}	// Insert the newly created *memorySource.	p.sources[name] = source}复制代码

经测试,该实现大约可以达到 1,400,000 插入/秒(通过协程并发调用,GOMAXPROCS 设置为 4)。看上去很快,但实际上它是慢于单个协程的,因为多个协程间存在锁竞争。

下面给出不存在竟态条件、线程安全,应该算是“正确”的版本了。使用了 RWMutex,读操作不会被锁,写操作保持同步。

var source *memorySourcevar present boolp.lock.RLock()if source, present = p.sources[name]; !present {	// The source wasn't found, so we'll create it.	p.lock.RUnlock()	p.lock.Lock()	if source, present = p.sources[name]; !present {		source = &memorySource{			name: name,			metrics: map[string]*memoryMetric{},		}		// Insert the newly created *memorySource.		p.sources[name] = source	}	p.lock.Unlock()} else {	p.lock.RUnlock()}复制代码

转载于:https://juejin.im/post/5c25cac1e51d451be35e5bde

你可能感兴趣的文章
第二阶段冲刺——six
查看>>
模块封装代码
查看>>
《Machine Learning》(第一章)序章
查看>>
【右键禁用U盘的小技巧】
查看>>
执行sql语句后的数据处理api
查看>>
jquery $.each的用法
查看>>
Python --元组与列表的差异
查看>>
PHP TP增删改
查看>>
VMware虚拟机与主机联通及配置上网
查看>>
single-row function和muti-row function
查看>>
keepalived
查看>>
意向锁
查看>>
线性规划
查看>>
常见错误分析-笔记
查看>>
P1256 显示图像(广搜)
查看>>
MongoDB(课时29 MapReduce)
查看>>
Slurm任务调度系统部署和测试(源码)(1)
查看>>
李超树详解
查看>>
怎样才是全能的程序员?
查看>>
with as的用法
查看>>