Go的bytes.Buffer类型是线程安全的吗?

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

Is the Go bytes.Buffer thread-safe?

问题

在Go编程语言中,bytes.Buffer是线程安全的吗?据我所知,它的文档没有提到线程安全性。

英文:

In the Go programming language, is bytes.Buffer thread-safe? AFAIK, its documentation does not mention thread safety.

答案1

得分: 32

不行。

Go的文档遵循一个简单的规则:如果没有明确说明对某个东西的并发访问是安全的,那就不是安全的。

英文:

No.

The Go documentation follows a simple rule: If it is not explicitly stated that concurrent access to something is safe, it is not.

答案2

得分: 21

不,但你可以很容易地将其封装在一个线程安全的结构体中!

对于简单的操作:

type Buffer struct {
    b bytes.Buffer
    m sync.Mutex
}

func (b *Buffer) Read(p []byte) (n int, err error) {
    b.m.Lock()
    defer b.m.Unlock()
    return b.b.Read(p)
}

func (b *Buffer) Write(p []byte) (n int, err error) {
    b.m.Lock()
    defer b.m.Unlock()
    return b.b.Write(p)
}

func (b *Buffer) String() string {
    b.m.Lock()
    defer b.m.Unlock()
    return b.b.String()
}

然后像使用 var buf Buffer 一样使用它。

如果需要更多 bytes.Buffer 的功能,可以自由选择:

func (b *Buffer) Bytes() []byte {
    b.m.Lock()
    defer b.m.Unlock()
    return b.b.Bytes()
}

func (b *Buffer) Cap() int {
    b.m.Lock()
    defer b.m.Unlock()
    return b.b.Cap()
}

// 其他方法省略...

这样可以确保在并发访问时的线程安全性。

英文:

No - but you can easily wrap it in a thread safe struct!

For simple things:

type Buffer struct {
	b bytes.Buffer
	m sync.Mutex
}
func (b *Buffer) Read(p []byte) (n int, err error) {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.Read(p)
}
func (b *Buffer) Write(p []byte) (n int, err error) {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.Write(p)
}
func (b *Buffer) String() string {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.String()
}

..and use it as usual var buf Buffer, etc.

Want more of bytes.Buffer? Feel free to cherry pick:

func (b *Buffer) Bytes() []byte {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.Bytes()
}
func (b *Buffer) Cap() int {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.Cap()
}
func (b *Buffer) Grow(n int) {
	b.m.Lock()
	defer b.m.Unlock()
	b.b.Grow(n)
}
func (b *Buffer) Len() int {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.Len()
}
func (b *Buffer) Next(n int) []byte {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.Next(n)
}
func (b *Buffer) ReadByte() (c byte, err error) {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.ReadByte()
}
func (b *Buffer) ReadBytes(delim byte) (line []byte, err error) {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.ReadBytes(delim)
}
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.ReadFrom(r)
}
func (b *Buffer) ReadRune() (r rune, size int, err error) {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.ReadRune()
}
func (b *Buffer) ReadString(delim byte) (line string, err error) {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.ReadString(delim)
}
func (b *Buffer) Reset() {
	b.m.Lock()
	defer b.m.Unlock()
	b.b.Reset()
}
func (b *Buffer) Truncate(n int) {
	b.m.Lock()
	defer b.m.Unlock()
	b.b.Truncate(n)
}
func (b *Buffer) UnreadByte() error {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.UnreadByte()
}
func (b *Buffer) UnreadRune() error {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.UnreadRune()
}
func (b *Buffer) WriteByte(c byte) error {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.WriteByte(c)
}
func (b *Buffer) WriteRune(r rune) (n int, err error) {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.WriteRune(r)
}
func (b *Buffer) WriteString(s string) (n int, err error) {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.WriteString(s)
}
func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
	b.m.Lock()
	defer b.m.Unlock()
	return b.b.WriteTo(w)
}

答案3

得分: 7

使用io.Pipe()函数调用,它提供了一对连接的对象(*PipeReader*PipeWriter)用于同步读写。这可以并行进行,并且是线程安全的。

英文:

Use io.Pipe() function call which provide pair of connected objects (*PipeReader, *PipeWriter) for synchronous read/write. This could be done in parallel, and it's a thread-safe.

答案4

得分: 0

bytes.Buffer不是线程安全的,但是这里有一个使用"通道和通信"安全地向Buffer(或任何io.StringWriter)写入的示例。

type SyncWriter struct {
	w      io.StringWriter
	finish sync.WaitGroup
	queue  chan string
	err    error
}

func NewSyncWriter(w io.StringWriter) *SyncWriter {
	var t SyncWriter
	t.w = w
	t.queue = make(chan string, 5)
	t.finish.Add(1)
	go t.writer()
	return &t
}

func (t *SyncWriter) Close() error {
	close(t.queue)
	t.finish.Wait()
	return t.err
}

func (t *SyncWriter) WriteString(s string) (int, error) {
	t.queue <- s
	return len(s), nil
}

func (t *SyncWriter) Write(p []byte) (int, error) {
	return t.WriteString(string(p))
}

func (t *SyncWriter) writer() {
	defer t.finish.Done()
	for s := range t.queue {
		_, err := t.w.WriteString(s)
		if err != nil && t.err == nil {
			t.err = err
		}
	}
}

以下是如何使用它的示例:

func write(wg *sync.WaitGroup, w io.Writer, d int) {
	fmt.Fprintf(w, "%d", d)
	wg.Done()
}

func main() {
	var buf bytes.Buffer
	w := NewSyncWriter(&buf)
	w.WriteString("hello ")
	var wg sync.WaitGroup
	wg.Add(10)
	for i := 0; i < 10; i++ {
		go write(&wg, w, i)
	}
	wg.Wait()
	w.Close()
	fmt.Printf("%s\n", buf.String())
}
英文:

bytes.Buffer is not thread safe, but here's an example of writing to a Buffer (or any io.StringWriter) safely using "channels and communication".

type SyncWriter struct {
	w      io.StringWriter
	finish sync.WaitGroup
	queue  chan string
	err    error
}

func NewSyncWriter(w io.StringWriter) *SyncWriter {
	var t SyncWriter
	t.w = w
	t.queue = make(chan string, 5)
	t.finish.Add(1)
	go t.writer()
	return &amp;t
}

func (t *SyncWriter) Close() error {
	close(t.queue)
	t.finish.Wait()
	return t.err
}

func (t *SyncWriter) WriteString(s string) (int, error) {
	t.queue &lt;- s
	return len(s), nil
}

func (t *SyncWriter) Write(p []byte) (int, error) {
	return t.WriteString(string(p))
}

func (t *SyncWriter) writer() {
	defer t.finish.Done()
	for s := range t.queue {
		_, err := t.w.WriteString(s)
		if err != nil &amp;&amp; t.err == nil {
			t.err = err
		}
	}
}

And here's how to use it:

func write(wg *sync.WaitGroup, w io.Writer, d int) {
	fmt.Fprintf(w, &quot;%d&quot;, d)
	wg.Done()
}

func main() {
	var buf bytes.Buffer
	w := NewSyncWriter(&amp;buf)
	w.WriteString(&quot;hello &quot;)
	var wg sync.WaitGroup
	wg.Add(10)
	for i := 0; i &lt; 10; i++ {
		go write(&amp;wg, w, i)
	}
	wg.Wait()
	w.Close()
	fmt.Printf(&quot;%s\n&quot;, buf.String())
}

huangapple
  • 本文由 发表于 2013年10月29日 07:07:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/19646717.html
匿名

发表评论

匿名网友

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

确定