Golang中Buffer高效拼接字符串以及自定义线程安全Buffer
Go中可以使用“+”合并字符串,但是这种合并方式效率非常低,每合并一次,都是创建一个新的字符串,就必须遍历复制一次字符串。Java中提供StringBuilder类(最高效,线程不安全)来解决这个问题。Go中也有类似的机制,那就是Buffer(线程不安全)。 以下是示例代码:package main import ( "bytes" "fmt" ) func main() { var buffer bytes.Buffer for i := 0; i < 1000; i++ { buffer.WriteString("a") } fmt.Println(buffer.String()) } 使用bytes.Buffer来组装字符串,不需要复制,只需要将添加的字符串放在缓存末尾即可。 Buffer为什么线程不安全?
以下是Golang中bytes.Buffer部分源码// A Buffer is a variable-sized buffer of bytes with Read and Write methods. // The zero value for Buffer is an empty buffer ready to use. type Buffer struct { buf []byte // contents are the bytes buf[off : len(buf)] off int // read at &buf[off],write at &buf[len(buf)] bootstrap [64]byte // memory to hold first slice; helps small buffers avoid allocation. lastRead readOp // last read operation,so that Unread* can work correctly. } // Write appends the contents of p to the buffer,growing the buffer as // needed. The return value n is the length of p; err is always nil. If the // buffer becomes too large,Write will panic with ErrTooLarge. func (b *Buffer) Write(p []byte) (n int,err error) { b.lastRead = opInvalid m := b.grow(len(p)) return copy(b.buf[m:],p),nil } // Read reads the next len(p) bytes from the buffer or until the buffer // is drained. The return value n is the number of bytes read. If the // buffer has no data to return,err is io.EOF (unless len(p) is zero); // otherwise it is nil. func (b *Buffer) Read(p []byte) (n int,err error) { b.lastRead = opInvalid if b.off >= len(b.buf) { // Buffer is empty,reset to recover space. b.Truncate(0) if len(p) == 0 { return } return 0,io.EOF } n = copy(p,b.buf[b.off:]) b.off += n if n > 0 { b.lastRead = opRead } return } 源码对于Buffer的定义中,并没有关于锁的字段,在write和read函数中也未发现锁的踪影,所以符合上面提到的文档中的rule,即Buffer并发是不安全的。 如何自定义实现一个并发安全的Buffertype Buffer struct { b bytes.Buffer rw sync.RWMutex } func (b *Buffer) Read(p []byte) (n int,err error) { b.rw.RLock() defer b.rw.RUnlock() return b.b.Read(p) } func (b *Buffer) Write(p []byte) (n int,err error) { b.rw.Lock() defer b.rw.Unlock() return b.b.Write(p) } 通过读写锁,解决并发读写问题,以上提供了Read和Write函数,亲,是不是Golang代码简洁明了?其它函数可以在Golang关于Buffer源码的基础上自行实现 两种锁的区别
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |