Golang的bytes.Buffer对于一个写入者/一个读取者的线程安全性。

huangapple go评论110阅读模式
英文:

Golang's bytes.Buffer thread safety for one writer/one reader

问题

我知道golang的bytes.Buffer不是线程安全的,但如果我有一个写入器(在一个goroutine中)和一个读取器(在另一个goroutine中),那么它是安全的吗?

如果不安全的话,为什么不安全?写入操作会将数据追加到缓冲区,而读取操作会从开头读取,所以我看不到它们会访问同一内存位置的情况。

英文:

I know that golang's bytes.Buffer is not thread-safe but if I have one writer (in a goroutine) and one reader (in another goroutine). Is it safe?

If not, then why is it not? Write appends to the buffer while reads read from the start so I don't see a scenario where they will be accessing the same memory location.

答案1

得分: 9

不,这是不安全的。

bytes.Buffer 是一个结构体,Buffer.Read()Buffer.Write() 方法都会读取/修改同一个结构体值的相同字段(它们都有指针接收器)。仅仅这一点就足以使其在并发使用时不安全。更多详情请参考 https://stackoverflow.com/questions/41406501/is-it-safe-to-read-a-function-pointer-concurrently-without-a-lock/41407827#41407827

此外,需要考虑到 bytes.Buffer 在字节切片中存储字节,而字节切片是结构体的一个字段。在写入时,有时可能需要分配一个更大的缓冲区(如果切片容量不足),因此必须更改切片头部(切片结构体字段)(在 Write() 中)。没有同步的情况下,无法保证并发的 Read() 将会看到这个更改。

而且...即使不需要重新分配(因为底层字节切片具有足够的容量来容纳传递给 Write() 的数据),将数据存储在字节切片中也需要对其进行重新切片,因此即使不需要重新分配,切片头部也会发生变化(切片的长度也是切片头部的一部分)。要查看切片头部的内容,请查看 reflect.SliceHeader 类型。

英文:

No, it's not safe.

bytes.Buffer is a struct, and both the Buffer.Read() and Buffer.Write() methods read / modify the same fields of the same struct value (they have pointer receivers). This alone is enough to be unsafe for concurrent use. For more details, see https://stackoverflow.com/questions/41406501/is-it-safe-to-read-a-function-pointer-concurrently-without-a-lock/41407827#41407827

Also think about that a bytes.Buffer stores bytes in a byte slice, which is a field of the struct. When writing, it might be necessary to sometimes allocate a bigger buffer (if slice capacity is not enough), and so the slice header (the slice struct field) must be changed (in Write()). Without synchronization there's no guarantee that a concurrent Read() will see this.

And... even if no reallocation is needed (because the underlying byte slice has enough capacity to accommodate the data passed to Write()), storing the data in the byte slice requires to reslice it, so the slice header changes even if no reallocation is needed (the length of the slice is also part of the slice header). To see what's in the slice header, check out the reflect.SliceHeader type.

huangapple
  • 本文由 发表于 2017年2月25日 01:57:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/42445301.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定