append()
的平均(摊销)成本已经是O(1),因为它的增长由每个时间的百分比的阵列。随着阵列变大,增长越来越昂贵,但比例更少。 10M物品切片比1M物品切片成本高出10倍,但由于我们分配的额外容量与大小成正比,因此它将成为许多append(slice, item)
调用的10倍,直到下一次增长。重新分配的成本增加和频率下降被抵消,使平均成本保持不变,即O(1)。例如,微软的std::vector
实现显然每次都会将数组增长50%。此外,微软的std::vector
实现也可以使数组增长50%。已摊销的O(1)并不意味着您不会为分配支付任何费用,只是您继续以与阵列变大的平均费率相同的价格付款。
在我的笔记本电脑上,我可以在77ms内运行100万个slice = append(slice, someStaticString)
秒。 siritinga下面提到的快速原因之一是,“复制”字符串以放大数组实际上只是复制字符串标头(指针/长度对),而不是复制内容。 100,000个字符串标题仍然小于2MB,与您正在处理的其他数据量相比,这不是什么大问题。
container/list
对于我来说,在微基准测试中慢了3倍;链接列表追加也是恒定的时间,当然,但我想append
有一个较低的常量,因为它通常可以写入一对单词的内存,而不是分配一个列表项等。时间码将无法在游乐场但你可以在本地复制此并运行它看到自己:http://play.golang.org/p/uYyMScmOjX
但是你在这里问一个更具体的问题有关grep
样的应用程序(和感谢要求具有上下文的详细问题)。为此,底线建议是,如果您搜索日志的演出,最好避免在RAM中缓冲整个输出。
你可以写一些东西来将结果作为单个函数进行流式传输:logparser.Grep(in io.Reader, out io.Writer, patterns []regexp.Regexp)
;如果您不希望发送结果的代码与grep代码过于紧密结合,您可以选择使out
为chan []byte
或func(match []byte) (err error)
。
(在[]byte
对比string
:一个[]byte
似乎在这里做的工作,避免[]byte
< =>string
转换,当你做I/O,所以我宁愿我不知道你”。再这样做,不过,如果你需要string
它的罚款。)
如果做保持在RAM中的整体匹配列表,要知道,围绕基准保持一个大的字符串或字节片的一部分保持整个源字符串/切片被垃圾收集。所以如果你走这条路线,那么违反直觉,你实际上可能会想要复制匹配,以避免将所有的源日志数据保存在RAM中。
鉴于数据TB的容量来处理我有限制的行数在一个运行扫描(原因应该是显而易见的:平均保持在I/O负载,CPU负载和驻留集大小,即防止大负荷峰),所以我不必真的流。但是更重要的是,我不明白你的意思,如果我溢出1M行,下一个操作将不会是1.25M行分配+复制1M行?请参阅下一个计算评论。 – LetMeSOThat4U
在Python中:a = 1; cumul = 0。然后'因为我在范围内(10):print'rows%.2f cumul%.2f'%(a,cumul),; cumul + = a; A = A * 1.25'。结果:行1.00累积0.00行1.25累积1.00行1.56累积2.25行1.95累积3.81行2.44累积5.77行3.05累积8.21行3.81累积11.26行4.77累积15.07行5.96累积19.84行7.45累积25.80。因此,如果我从1M行切片开始,并且有800万个匹配需要复制切片10次,并复制总计25M行。与链接列表相比,这不是一个非常好的成本.. – LetMeSOThat4U
我认为一段字符串在内部是一个指向字符串的指针切片,从某种意义上说,扩展切片不会真正复制字符串,只是指向字符串,因此每个条目都是4或8个字节(取决于系统架构),所以它应该很快。 – siritinga