【发布时间】:2017-10-31 17:16:21
【问题描述】:
正如您在以下 pprof 输出中所见,我有这些嵌套的 for 循环,这些循环占用了我程序的大部分时间。源码是golang,代码解释如下:
8.55mins 1.18hrs 20: for k := range mapSource {
4.41mins 1.20hrs 21: if positions, found := mapTarget[k]; found {
. . 22: // save all matches
1.05mins 1.05mins 23: for _, targetPos := range positions {
2.25mins 2.33mins 24: for _, sourcePos := range mapSource[k] {
1.28s 15.78s 25: matches = append(matches, match{int32(targetPos), int32(sourcePos)})
. . 26: }
. . 27: }
. . 28: }
. . 29: }
目前我使用的结构是 2 map[int32][]int32,targetMap 和 sourceMap。
对于给定的键,这些映射包含一个整数数组。现在我想在两个映射中找到匹配的键,并将元素的组合保存在数组中。
例如:
sourceMap[1] = [3,4]
sourceMap[5] = [9,10]
targetMap[1] = [1,2,3]
targetMap[2] = [2,3]
targetMap[3] = [1,2]
唯一的共同键是1,结果是[(3,1), (3,2), (3,3), (4,1), (4,2), (4,3)]
是否有任何可能的方式(更合适的数据结构或其他)可以提高我的程序速度?
在我的例子中,map 可以包含 1000 到 150000 个键,而里面的数组通常很小。
编辑:并发不是一个选项,因为它已经在多个线程中同时运行了多次。
【问题讨论】:
-
一方面,您可以获取最外层循环中的值 (
for k :=->for k,v :=),这将消除最内层循环中的额外查找 (:= range mapSource[k]->:= range v)。也无需将targetPos和sourcePos转换为int32,因为根据您的问题它们已经是int32。总体而言,尽管地图可能是最有效的结构。如果您对最终数据集的大小或最小大小有所了解,可以使用该容量预先分配matches。 -
数组总是排序的(就像你的例子一样)?
-
不确定它会有多大帮助,但
for _, x := range slice {格式将重新声明 x 并在每次迭代时为其分配值。尝试改用索引值,看看它是否有帮助。for i := range slice { ... slice[i] -
@dave 是的,他们是
-
也许保留另一个源键映射 ==> 目标键。这将删除每个源键的目标映射的顺序迭代。
标签: performance go complexity-theory