Golang中Buffer高效拼接字符串以及自定義線程安全Buffer

Go中可以使用“+”合并字符串,但是這種合并方式效率非常低店溢,每合并一次瘫筐,都是創(chuàng)建一個新的字符串,就必須遍歷復制一次字符串。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文檔遵循一個簡單的規(guī)則:如果沒有明確聲明并發(fā)訪問某事物是安全的看蚜,則不是。

以下是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函數(shù)中也未發(fā)現(xiàn)鎖的蹤影,所以符合上面提到的文檔中的rule,即Buffer并發(fā)是不安全的赔桌。

如何自定義實現(xiàn)一個并發(fā)安全的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)
}

通過讀寫鎖,解決并發(fā)讀寫問題,以上提供了Read和Write函數(shù),親,是不是Golang代碼簡潔明了?其它函數(shù)可以在Golang關于Buffer源碼的基礎上自行實現(xiàn)

兩種鎖的區(qū)別
sync.Mutex(互斥鎖) sync.RWMutex(讀寫鎖)
當一個goroutine訪問的時候供炎,其他goroutine都不能訪問渴逻,保證了資源的同步,避免了競爭音诫,不過也降低了性能 非寫狀態(tài)時:多個Goroutine可以同時讀,一個Goroutine寫的時候,其它Goroutine不能讀也不能寫,性能好
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末惨奕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子竭钝,更是在濱河造成了極大的恐慌梨撞,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件香罐,死亡現(xiàn)場離奇詭異卧波,居然都是意外死亡,警方通過查閱死者的電腦和手機庇茫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門港粱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人旦签,你說我怎么就攤上這事查坪。” “怎么了宁炫?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵偿曙,是天一觀的道長。 經(jīng)常有香客問我羔巢,道長望忆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任朵纷,我火速辦了婚禮炭臭,結果婚禮上永脓,老公的妹妹穿的比我還像新娘袍辞。我一直安慰自己,他們只是感情好常摧,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布搅吁。 她就那樣靜靜地躺著,像睡著了一般落午。 火紅的嫁衣襯著肌膚如雪谎懦。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天溃斋,我揣著相機與錄音界拦,去河邊找鬼。 笑死梗劫,一個胖子當著我的面吹牛享甸,可吹牛的內(nèi)容都是我干的截碴。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼蛉威,長吁一口氣:“原來是場噩夢啊……” “哼日丹!你這毒婦竟也來了?” 一聲冷哼從身側響起蚯嫌,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤哲虾,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后择示,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體束凑,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年栅盲,在試婚紗的時候發(fā)現(xiàn)自己被綠了湘今。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡剪菱,死狀恐怖摩瞎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情孝常,我是刑警寧澤旗们,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站构灸,受9級特大地震影響上渴,放射性物質發(fā)生泄漏。R本人自食惡果不足惜喜颁,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一稠氮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧半开,春花似錦隔披、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至纠永,卻和暖如春鬓长,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背尝江。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工涉波, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓啤覆,卻偏偏與公主長得像善延,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子城侧,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容