如何使用互斥体有效地读写映射



我正在读取一个json文件,该文件包含1kk以上的对象,我需要组织并计数一些数据。为此,我创建了两个映射,以便可以对其进行写入和读取。当我运行一个简单的循环时,代码需要40秒才能完成,例如:

var acc int
firstContent := make(map[string]int)
secondContent := make(map[string]int)
decoder := json.NewDecoder(bufio.NewReader(file))
for decoder.More() {
var dt &MyStruct{}
decoder.Decode()
if _, ok := firstContent[dt.Name]; !ok {
firstContent["some-data"] = 1
acc++ // count the uniqueness
} else {
firstContent["some-data"] += 1
}
if _, ok := secondContent[dt.City]; !ok {
first["some-data"] = 1
} else {
first["some-data"] += 1
}
}

我尝试使用goroutinesmutex进行优化以避免并发,但当我使用它时,需要更长的时间才能完成。

var mutex = sync.RWMutex{}
for reader.More() {
var dt &MyStruct{}
reader.Decode(&dt)
go func(name string) {
mutex.Lock()
if _, ok := firstContent[name]; !ok {
firstContent[name] = 1 // need to convert to *int64, i know...
atomic.AddInt32(acc, 1)
} else {
atomic.AddInt64(firstContent[name], 1)
}
mutex.Unlock()
}(dt.Name)
go func(city string) {
mutex.Lock()
if _, ok := secondContent[city]; !ok {
secondContent[city] = 1
} else {
atomic.AddInt(secondContent[city], 1)
}
mutex.Unlock()
}(dt.City)
}

为什么要花更长的时间才能完成?因为mutex.Lock()?在这种情况下,我该如何提高速度?

您的问题无法通过一致性解决。需要花费大部分时间的是解析json,而不计算名称。您可以说,这种情况有点自相矛盾,因为您必须在单个线程上读取文件。也许将文件拆分成更小的文件并在单独的线程上处理每个文件会有所帮助,当然前提是您可以这样做。

就像上面Jakub所说的,你可以分割输入文件并在单独的goroutine上处理(比如MapReduce框架(,这肯定会加快速度。

此外,您是否尝试过在JSON文件中创建对象的go结构,并将其编组为对象列表,然后从中进行计算?不确定这是否会更好,但这是一个想法。

最新更新