当我们可以存储在字符串变量中时缓冲区的目的是什么?

时间:2016-01-08 19:36:45

标签: go

为什么我可以在连接字符串时使用缓冲区?

以下PSEUDO代码

var buffer bytes.Buffer 
for i := 0; i < 200; i++ {
    buffer.WriteString(strconv.Itoa(i))
}
fmt.Println(buffer.String())

Vs的

buffer := ""
for i := 0; i < 200; i++ {
    buffer += strconv.Itoa(i)
}
fmt.Println(buffer)

3 个答案:

答案 0 :(得分:7)

缓冲区以块的形式增长以分摊内存分配。

因为字符串是不可变的,所以循环中的每次迭代都必须分配一个新的字符串。

答案 1 :(得分:3)

您可以将缓冲区视为排队的队列。每个人都只是排在第一位,它非常高效,并没有占用额外的空间来添加新物品。你只需插入它们就可以了。

因此,当您将A,B,C,D,E添加到缓冲区时,操作看起来有点像这样的内存:

buffer=A
buffer=A|B
buffer=A|B|C
buffer=A|B|C|D
buffer=A|B|C|D|E

现在,如果你连接字符串,就必须分配和重新分配大量内存

 str=''
 str=Allocate(A),allocate(str+A),deallocate(str='')
 str=Allocate(B),allocate(str(''|A)+B),deallocate(str=''|A)
 str=Allocate(C),allocate(str(''|A|B)+C),deallocate(str=''|A|B)
 str=Allocate(D),allocate(str(''|A|B|C)+D),deallocate(str=''|A|B|C)
 str=Allocate(E),allocate(str(''|A|B|C|D)+E),deallocate(str=''|A|B|C|D)

正如您所看到的,通过不断向字符串添加一个由旧字符串组成的新字符串,然后创建新字符串并释放旧字符串。
这会导致很多垃圾内存。当你添加一个缓冲区时,你只需整齐地排列所有内容,而不需要占用额外的内存。

如果你连接字符串,你会不断分配更新更大的变量。 Oldstring +追加字符串+新的concat字符串。这种增长,成长和增长 如果你有一个大文件,你逐行阅读,这可能会在一段时间后给出一些内存不足的错误。

答案 2 :(得分:2)

字符串在Go中是不可变的。因此第二个示例将在每次迭代时分配一个新字符串,因此将具有O(n ^ 2)运行时。