当前位置: 首页 > 面试题库 >

有效地附加到可变长度的字符串容器(Golang)

杜嘉木
2023-03-14
问题内容

问题:

我需要将多个正则表达式应用于大日志文件的每一行(例如几GB长),收集非空匹配项并将其全部放入数组中(用于序列化并通过网络发送)。

如果对此问题的答案成立,切片没有多大帮助:

如果分片没有足够的容量,则append将需要分配新的内存并复制旧的内存。对于具有<1024个元素的片,它将使容量加倍;对于具有>
1024个元素的片,它将使容量增加1.25倍。

由于实际上可以有成千上万个正则表达式匹配,所以我无法真正预测切片的长度/容量。我不能太大,以防万一,这会浪费内存(或者会吗?如果内存分配器足够聪明,不能分配太多未写入的内存,也许我可以使用巨大的分片容量没有太大的伤害?)。

所以我正在考虑以下替代方案:

  1. 有一个双向链接的匹配列表(http://golang.org/pkg/container/list/)
  2. 计算其长度(len()行得通吗?)
  3. 预分配此容量的一部分
  4. 将字符串指针复制到此切片

Go中是否有较省力的方法来实现此目标(附加〜O(1)附加复杂性)?

(当然是golang新手)


问题答案:

append()平均(摊销)成本已经是O(1),因为它每次都会使数组增加一个百分比。随着阵列变大,增长变得越来越昂贵,但比例却越来越少。10M项切片的增长成本比1M项切片的成本高10倍,但是由于我们分配的额外容量与大小成正比,因此append(slice,item)在下一次增长之前,其调用数也将是其10倍。重新分配的增加的成本和减少的频率会抵消,从而使平均成本保持不变,即O(1)。

同样的想法也适用于其他语言的动态大小的数组:例如,Microsoft的std::vector实现显然每次将数组增长50%。摊销O(1)并不意味着您无需为分配支付任何费用,只是意味着您继续以与数组变大相同的平均费率支付费用。

在我的笔记本电脑上,我可以slice = append(slice,someStaticString)在77毫秒内运行一百万秒。siritinga在下面指出,它之所以很快是一个原因,就是“复制”字符串以扩大数组实际上只是复制字符串标题(指针/长度对),而不是复制内容。100,000个字符串标题仍不足2MB进行复制,与您要处理的其他数据量相比,这并不算什么。

container/list在微基准测试中,我的速度降低了约3倍;当然,链表附加也是固定时间,但是我想 append它的常数较低,因为它通常只能写到几个内存中,而不分配列表项,等等。计时码在Playground中不起作用但您可以在本地复制并运行它以查看自己的身份: http
//play.golang.org/p/uYyMScmOjX

但是您在这里询问有关类似grep应用程序的更具体问题(并感谢您提出有关上下文的详细问题)。为此,最重要的建议是,如果您要搜索大量的日志,则最好避免完全在RAM中缓冲整个输出。

你可以写的东西流的结果作为一个单一的功能:logparser.Grep(in io.Reader, out io.Writer, patterns []regexp.Regexp); 你可以或者让out一个chan []byte或者func(match []byte) (err error),如果你不希望将结果发送到与grep的代码过于沉浸代码。

(在[]bytevs上string:在您执行I / O时,a[]byte似乎可以完成此工作,并且避免了[]byte<=>
string转换,所以我更愿意这样做。但是,我不知道您在做什么,以及是否需要string没关系。)

如果 确实_将整个匹配列表保留在RAM中,请注意,保留对大字符串或字节片的一部分的引用可以防止整个源字符串/片被垃圾回收。因此,如果走那条路线,那么反直觉地,您实际上可能
_想要
复制匹配项,以避免将所有源日志数据保留在RAM中。



 类似资料:
  • 问题是: 我需要对一个大日志文件的每一行应用多个正则表达式(比如几GB长),收集非空匹配并将它们全部放入一个数组中(用于序列化并通过网络发送)。 如果这个问题的答案是正确的,那么切片并没有多大帮助: 如果片没有足够的容量,append将需要分配新内存并复制旧内存。用于切片 因为可以有几十万个正则表达式匹配,所以我无法真正预测一个片段的长度/容量。我也不能让它太大,“以防万一”bc这会浪费内存(或者

  • 问题内容: 我有可变数量的ArrayList,我需要找到它的交集。一组实际的字符串数量上限可能约为35个,但可能更多。我不需要任何代码,只是想一些有效率的想法。我有一个即将开始编码的实现,但想听听其他想法。 目前,仅考虑我的解决方案,看起来我应该具有Θ(n 2)的渐近运行时间。 谢谢你的帮助! 切碎 编辑:澄清一下,我真的只是想知道是否有一种更快的方法。快于Θ(n 2)。 问题答案: 是找到两个集

  • 问题内容: 我写了一个Java程序,其中需要附加一个字符串 到现有的。 因此,字符串逐渐变长。我发现每次附加所花费的时间也越来越长。有什么办法可以改善这一点? 我想到的实现包括: 要么 他们表现相似。我认为导致这些不良性能的主要原因是特殊类型。它为每个作业创建一个新对象。如果您也这样认为,这是否意味着我最好使用其他类型,例如字节数组? 问题答案: 使用类。您尝试执行的操作效率更高。

  • 问题内容: 数据如下所示: 我希望它看起来像这样: 摆脱一个或另一个很简单。 这: 给我这样的建议:倡议:可信来源倡议:及时的倡议:数据库规范化 还有这个: 给我这个: 很难弄清楚如何将两者结合起来。 问题答案: 只是使用怎么样? 或者,如果您不知道前缀有多长时间: 这是一个。

  • 问题内容: 我有一个带有列的表,其中包含如下所示的字符串。 我需要从第二次出现到字符串结尾获取子字符串,并且您可以看到子字符串的长度不是固定的。第一部分并不总是固定的,它可以改变。到目前为止,我正在使用以下代码来实现它。 如您所见,我采用一个任意大的值作为长度来处理可变长度。有更好的方法吗? 问题答案: 您可以与函数结合使用,找到的最后一次出现,还可以使用从字符串末尾获取指定数量的字符。 SQLF

  • 如果我想将char数组中的前3个字符作为双精度字符进行解析,而忽略以下字符,那么我真的需要这样做吗? 难道没有一个像这样的函数允许您指定它应该搜索的数字的最大字符串长度吗? 编辑:我希望它打印(它目前这样做),而不是!