在 Go 编程语言中,
bytes.Buffer
是否支持多线程?据我所知,它的文档并未提及其线程安全性。不行。
Go语言的文档遵循一个简单的规则:如果没有明确说明对某个东西的并发访问是安全的,那么它就不是安全的。
不行 - 但你可以轻松地将它包装在一个线程安全的结构体中!
对于简单的事情:
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()
}
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)
}
也许是 rwmux?
。实际上,bytes.Buffer
在 Read()
中会更改数据,因此即使使用了 rwmux,仍必须使用写锁。但是,如果使用不同的缓冲区实现,则使用 rwmux 可能会增加吞吐量。 - xiaoyi使用io.Pipe()
函数调用,它提供了一对连接对象(*PipeReader
、*PipeWriter
),用于同步读/写。这可以并行完成,而且是线程安全的。
io.Pipe()
”是一个很好的起点,但还有很多工作要做。 - Abhijit Sarkarbytes.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())
}