成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Go語言 | 基于 Channel 實現的并發安全的字節池

開發 前端
sync.Pool可以存放任何對象,BytePoolCap只能存放[]byte,不過也正因為其自定義,存放的對象類型明確,不用經過一層類型斷言轉換,同時也可以自己定制對象池的大小等。

字節切片[]byte是我們在編碼中經常使用到的,比如要讀取文件的內容,或者從io.Reader獲取數據等,都需要[]byte做緩沖。

func ReadFull(r Reader, buf []byte) (n int, err error)
func (f *File) Read(b []byte) (n int, err error)

以上是兩個使用到[]byte作為緩沖區的方法。那么現在問題來了,如果對于以上方法我們有大量的調用,那么就要聲明很多個[]byte,這需要太多的內存的申請和釋放,也就會有太多的GC。

MinIO 的字節池

這個時候,我們需要重用已經創建好的[]byte來提高對象的使用率,降低內存的申請和GC。這時候我們可以使用sync.Pool來實現,不過最近我在研究開源項目MinIO的時候,發現他們使用channel的方式實現字節池。

type BytePoolCap struct {
c chan []byte
w int
wcap int
}

BytePoolCap結構體的定義比較簡單,共有三個字段:

  1. c是一個chan,用于充當字節緩存池
  2. w是指使用make函數創建[]byte時候的len參數
  3. wcap指使用make函數創建[]byte時候的cap參數

有了BytePoolCap結構體,就可以為其定義Get方法,用于獲取一個緩存的[]byte了。

func (bp *BytePoolCap) Get() (b []byte) {
select {
case b = <-bp.c:
// reuse existing buffer
default:
// create new buffer
if bp.wcap > 0 {
b = make([]byte, bp.w, bp.wcap)
} else {
b = make([]byte, bp.w)
}
}
return
}

以上是采用經典的select+chan的方式,能獲取到[]byte緩存則獲取,獲取不到就執行default分支,使用make函數生成一個[]byte。

從這里也可以看到,結構體中定義的w和wcap字段,用于make函數的len和cap參數。

有了Get方法,還要有Put方法,這樣就可以把使用過的[]byte放回字節池,便于重用。

func (bp *BytePoolCap) Put(b []byte) {
select {
case bp.c <- b:
// buffer went back into pool
default:
// buffer didn't go back into pool, just discard
}
}

Put方法也是采用select+chan,能放則放,不能放就丟棄這個[]byte。

使用BytePoolCap

已經定義好了Get和Put就可以使用了,在使用前,BytePoolCap還定義了一個工廠函數,用于生成*BytePoolCap,比較方便。

func NewBytePoolCap(maxSize int, width int, capwidth int) (bp *BytePoolCap) {
return &BytePoolCap{
c: make(chan []byte, maxSize),
w: width,
wcap: capwidth,
}
}

把相關的參數暴露出去,可以讓調用者自己定制。這里的maxSize表示要創建的chan有多大,也就是字節池的大小,最大存放數量。

bp := bpool.NewBytePoolCap(500, 1024, 1024)
buf:=bp.Get()
defer bp.Put(buf)

//使用buf,不再舉例

以上就是使用字節池的一般套路,使用后記得放回以便復用。

和sync.Pool對比

兩者原理基本上差不多,都多協程安全。sync.Pool可以存放任何對象,BytePoolCap只能存放[]byte,不過也正因為其自定義,存放的對象類型明確,不用經過一層類型斷言轉換,同時也可以自己定制對象池的大小等。

關于二者的性能,我做了下Benchmark測試,整體看MinIO的BytePoolCap更好一些。

var bp = bpool.NewBytePoolCap(500, 1024, 1024)
var sp = &sync.Pool{
New: func() interface{} {
return make([]byte, 1024, 1024)
},
}

模擬的兩個字節池,[]byte的長度和容量都是1024。然后是兩個模擬使用字節池,這里我啟動500協程,模擬并發,使用不模擬并發的話,BytePoolCap完全是一個[]byte的分配,完全秒殺sync.Pool,對sync.Pool不公平。

func opBytePool(bp *bpool.BytePoolCap) {
var wg sync.WaitGroup
wg.Add(500)
for i := 0; i < 500; i++ {
go func(bp *bpool.BytePoolCap) {
buffer := bp.Get()
defer bp.Put(buffer)
mockReadFile(buffer)
wg.Done()
}(bp)
}
wg.Wait()
}

func opSyncPool(sp *sync.Pool) {
var wg sync.WaitGroup
wg.Add(500)
for i := 0; i < 500; i++ {
go func(sp *sync.Pool) {
buffer := sp.Get().([]byte)
defer sp.Put(buffer)
mockReadFile(buffer)
wg.Done()
}(sp)
}
wg.Wait()
}

接下來就是我模擬的讀取我本機文件的一個函數mockReadFile(buffer)

func mockReadFile(b []byte) {
f, _ := os.Open("water")
for {
n, err := io.ReadFull(f, b)
if n == 0 || err == io.EOF {
break
}
}
}

然后運行go test -bench=. -benchmem -run=none 查看測試結果:

pkg: flysnow.org/hello
BenchmarkBytePool-8 1489 979113 ns/op 36504 B/op 1152 allocs/op
BenchmarkSyncPool-8 1008 1172429 ns/op 57788 B/op 1744 allocs/op

從測試結果看BytePoolCap在內存分配,每次操作分配字節,每次操作耗時來看,都比sync.Pool更有優勢。

小結

很多優秀的開源項目,可以看到很多優秀的源代碼實現,并且會根據自己的業務場景,做出更好的優化。

本文轉載自微信公眾號「飛雪無情」,可以通過以下二維碼關注。轉載本文請聯系飛雪無情公眾號。

責任編輯:武曉燕 來源: 飛雪無情
相關推薦

2021-09-30 09:21:28

Go語言并發編程

2023-05-15 08:01:16

Go語言

2024-06-19 10:08:34

GoChannel工具

2024-09-06 10:48:13

2013-05-28 09:43:38

GoGo語言并發模式

2021-07-15 23:18:48

Go語言并發

2023-12-21 07:09:32

Go語言任務

2021-07-30 07:28:15

WorkerPoolGo語言

2024-04-07 00:04:00

Go語言Map

2024-06-06 09:47:56

2025-04-02 05:23:00

GoChannel數據

2020-12-27 10:15:44

Go語言channel管道

2024-07-01 08:44:42

Go語言協程

2025-02-05 12:09:12

2021-07-26 09:47:38

Go語言C++

2023-01-30 08:16:39

Go語言Map

2024-02-21 12:14:00

Gochannel?panic?

2022-09-04 23:24:45

Go語言監控

2023-04-06 08:01:30

RustMutex

2021-06-24 06:35:00

Go語言進程
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品成人一区二区三区 | 在线观看亚洲专区 | 在线视频中文字幕 | 宅女噜噜66国产精品观看免费 | 国产精品一区二区三级 | 亚洲精品久久久久久国产精华液 | 伊人网影院 | 久久久性色精品国产免费观看 | 99精品网站| 成人精品视频免费 | 黄色片在线网站 | 在线看片国产精品 | 97国产精品 | 亚洲一区二区三区四区av | 国产精品久久福利 | 精品不卡 | 欧美一区2区三区4区公司 | 亚洲网站在线观看 | 亚洲国产精品视频一区 | 免费视频一区二区 | 色综合久久天天综合网 | 亚洲网在线 | 一级片子 | 成人精品在线视频 | 久久婷婷香蕉热狠狠综合 | 一区二区三区视频免费观看 | 美女天天操 | 免费三级av | 美日韩中文字幕 | 亚洲一区二区三区在线播放 | 日本天天操| 成人亚洲一区 | 欧美激情视频一区二区三区在线播放 | 日韩国产在线 | 亚洲视频在线观看 | 操人视频在线观看 | 亚洲 精品 综合 精品 自拍 | 成年人精品视频 | 国产精品视频 | 在线不卡视频 | 国产精品综合色区在线观看 |