golang中apend_Golang中Slice的append详解

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为什么线程不安全?

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

Go文档遵循一个简单的规则:如果没有明确声明并发访问某事物是安全的,则不是。

以下是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并发是不安全的。

如何自定义实现一个并发安全的Buffer

type 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源码的基础上自行实现

两种锁的区别

sync.Mutex(互斥锁)

sync.RWMutex(读写锁)

当一个goroutine访问的时候,其他goroutine都不能访问,保证了资源的同步,避免了竞争,不过也降低了性能

非写状态时:多个Goroutine可以同时读,一个Goroutine写的时候,其它Goroutine不能读也不能写,性能好

你可能感兴趣的:(golang中apend)