帶緩衝的寫並且讀取固定大小byte陣列的物件設計

lifei6671發表於2018-07-31

目前有這樣一個需求,需要多個 goroutine 來寫。多個 goroutine 來讀。但是寫的時候必須組裝成固定大小的 byte 陣列後才能被讀取,否則就等待下一次寫,知道足夠大。

直到關閉物件後,將剩餘的 byte 陣列都放入佇列。

目前設計如下,感覺存在一些問題,請罈子裡的牛人給寫建議,如何設計更優雅呢?

package blob

import (
    "sync"
    "errors"
    "sync/atomic"
)

var ErrClosedBuffer = errors.New("io: read/write on closed buffer")
var ErrBufferNotFull = errors.New("bufio: buffer not full")

type BufferWriterReader struct {
    wMu  sync.Mutex // Serializes Write operations
    buf  []byte
    n, c int //n 每個byte陣列的大小,c 一共剩餘的佇列長度
    wCh  chan []byte

    size int
    done uint32
    once sync.Once
}

//從緩衝區中讀取一個陣列,該陣列長度可能會小於設定的緩衝長度
func (p *BufferWriterReader) ReadBytes() (buf []byte, err error) {
    //如果緩衝已關閉,佇列已讀完
    if atomic.LoadUint32(&p.done) == 1 && p.c == 0 {
        return nil, ErrClosedBuffer
    }
    if p.c > 0 {
        err = nil
        buf = <-p.wCh
        p.c = p.c - 1
    } else {
        return nil, ErrBufferNotFull
    }
    return
}

func (p *BufferWriterReader) Write(b []byte) (n int, err error) {

    if atomic.LoadUint32(&p.done) == 1 {
        return 0, ErrClosedBuffer
    }
    p.wMu.Lock()
    defer p.wMu.Unlock()
    //需要將p.buf填滿到指定長度才能放到channel中等待讀取
    for once := true; once || len(b) > 0; once = false {
        //緩衝區剩餘位元組
        l := p.size - p.n
        i := 0
        if l >= len(b) {
            i = copy(p.buf[p.n:], b)
            b = b[:0]
        } else {
            i = copy(p.buf[p.n:], b)
            b = b[l+1:]
        }

        p.n += i

        if p.n == p.size {
            p.wCh <- p.buf
            p.n = 0
            p.buf = make([]byte, p.size)
            p.c ++
        }

        if len(b) > 0 {
            once = true
        }
    }
    return n, nil
}

func (b *BufferWriterReader) Close() error {

    b.once.Do(func() {
        //呼叫關閉方法後,將p.buf放入到channel
        atomic.AddUint32(&b.done, 1)
        if  b.n > 0 {
            b.wCh <- b.buf
            b.n = 0
            b.buf = make([]byte, b.size)
            b.c ++
        }
        close(b.wCh)
    })

    return nil

}

func NewBufferWriterReaderSize(rSize int, wSize int) *BufferWriterReader {
    return &BufferWriterReader{
        wMu:  sync.Mutex{},
        buf:  make([]byte, rSize),
        wCh:  make(chan []byte, wSize),
        done: 0,
        n:    0,
        c:    0,
        size: rSize,
    }
}

更多原創文章乾貨分享,請關注公眾號
  • 帶緩衝的寫並且讀取固定大小byte陣列的物件設計
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章