【发布时间】:2020-11-19 09:02:12
【问题描述】:
我在 Go 中有一个坐标对 ([x, y]) 的 FIFO 队列:
type Copair [2]int
type Queue []Copair
var q = Queue{ ... preloaded values ... }
API 定义如下,其中重要的部分是pop() 函数:
func (q Queue) push(p Copair) {
q = append(q, p)
}
func (q Queue) pop() (error, Copair) {
if q != nil && len(q) >= 1 {
q = q[1:]
return nil, q[0]
} else {
return errors.New("index out of range [0]"), nil
}
}
在q = q[1:] 中,我正在重新构建切片,理论上它应该只需要在内存中更改一个地址,因此是一个恒定时间操作。现在,我们正在逐渐丢失堆上的字节(或者谁知道,Go 的逃逸分析可能足够聪明,可以将它放在堆栈上),我希望垃圾收集器可以回收这些字节以避免内存泄漏,最终我们将到达堆边界,运行时将不得不将整个队列复制到其他地方,这肯定是线性时间操作。但是……
q = q[1:] 执行的切片重构是恒定时间操作,还是与队列大小成线性关系?如果(正如我所怀疑的)答案是“哦,非常”“它取决于”,它依赖的条件是什么,是否有任何简单的经验法则可以解决这个问题?
【问题讨论】:
-
“应该只需要在内存中更改一个地址”它需要更改一个值,但它不是地址,而是索引。 “我希望垃圾收集器可以回收这些字节”不,它不能;切片是对底层数组的引用,该数组的大小没有变化,只有切片覆盖的窗口。
-
我可以要求一些建设性的反馈,说明为什么这被否决了吗?这似乎是一个完全合理的问题,如果我犯了一些大错误,我希望能够在未来改进我的问题:)
标签: go memory time-complexity slice