Go語言io?pipe源碼分析詳情
pipe.go分析:
- 這個(gè)文件使用到了errors包,也是用到了sync庫.
- 文件說明:pipe是一個(gè)適配器,用于連接Reader和Writer.
1.結(jié)構(gòu)分析
對(duì)外暴露的是一個(gè)構(gòu)造函數(shù)和構(gòu)造的兩個(gè)對(duì)象. 兩個(gè)對(duì)象分別暴露了方法,同時(shí)這兩個(gè)對(duì)象還有一個(gè)共同的底層對(duì)象. 實(shí)際上,這兩個(gè)對(duì)象暴露的方法是直接調(diào)用底層對(duì)象的, 那么核心還是在底層對(duì)象上,只是通過兩個(gè)對(duì)象和一個(gè)構(gòu)造方法將底層對(duì)象的細(xì)節(jié)隱藏了.
2.pipe sruct分析
pipe的方法不多,新的寫法卻不少.
type atomicError struct{ v atomic.Value } ? ? func (a *atomicError) Store(err error) { ? ? ? a.v.Store(struct{ error }{err}) ? ? } ? ? func (a *atomicError) Load() error { ? ? ? err, _ := a.v.Load().(struct{ error }) ? ? ? return err.error ? ? }
atomicError提供了error的原子讀寫.
? type pipe struct { ? ? ? wrMu sync.Mutex // Serializes Write operations ? ? ? wrCh chan []byte ? ? ? rdCh chan int ? ? ? once sync.Once // Protects closing done ? ? ? done chan struct{} ? ? ? rerr atomicError ? ? ? werr atomicError ? ? }
可以看到pipe結(jié)構(gòu)體中主要分兩塊:
- 讀寫信道
- 兩個(gè)無緩沖信道
- 一個(gè)互斥量(保護(hù)暴露的寫函數(shù))
- 結(jié)束標(biāo)識(shí)
- once保證done的關(guān)閉只執(zhí)行一次
- done標(biāo)志整個(gè)讀寫的結(jié)束
- 剩下兩個(gè)用于存儲(chǔ)讀寫錯(cuò)誤
- PipeReader/PipeWriter的分析
3.PipeReader對(duì)外暴露的是讀/關(guān)閉
? ? type PipeReader struct { ? ? ? p *pipe ? ? } ? ? func (r *PipeReader) Read(data []byte) (n int, err error) { ? ? ? return r.p.Read(data) ? ? } ? ? func (r *PipeReader) Close() error { ? ? ? return r.CloseWithError(nil) ? ? } ? ? func (r *PipeReader) CloseWithError(err error) error { ? ? ? return r.p.CloseRead(err) ? ? }
PipeWriter對(duì)外暴露的是寫/關(guān)閉
? ?type PipeWriter struct { ? ? ? ?p *pipe ? ? ?} ? ? func (w *PipeWriter) Write(data []byte) (n int, err error) { ? ? ? return w.p.Write(data) ? ? } ? ? func (w *PipeWriter) Close() error { ? ? ? return w.CloseWithError(nil) ? ? } ? ? func (w *PipeWriter) CloseWithError(err error) error { ? ? ? return w.p.CloseWrite(err) ? ? }
他們的方法集都是指針接收者.具體方法的實(shí)現(xiàn)是通過pipe
的方法完成的. pipe的方法更加明確:讀/獲取讀錯(cuò)誤/結(jié)束讀寫并設(shè)置讀錯(cuò)誤; 寫/獲取寫錯(cuò)誤/結(jié)束讀寫并設(shè)置寫錯(cuò)誤.思路相當(dāng)明確.
下面主要分析pipe的讀寫
? func (p *pipe) Read(b []byte) (n int, err error) { ? ? ? select { ? ? ? case <-p.done: ? ? ? ? return 0, p.readCloseError() ? ? ? default: ? ? ? } ? ? ? select { ? ? ? case bw := <-p.wrCh: ? ? ? ? nr := copy(b, bw) ? ? ? ? p.rdCh <- nr ? ? ? ? return nr, nil ? ? ? case <-p.done: ? ? ? ? return 0, p.readCloseError() ? ? ? } ? ? } ? ? func (p *pipe) Write(b []byte) (n int, err error) { ? ? ? select { ? ? ? case <-p.done: ? ? ? ? return 0, p.writeCloseError() ? ? ? default: ? ? ? ? p.wrMu.Lock() ? ? ? ? defer p.wrMu.Unlock() ? ? ? } ? ? ? for once := true; once || len(b) > 0; once = false { ? ? ? ? select { ? ? ? ? case p.wrCh <- b: ? ? ? ? ? nw := <-p.rdCh ? ? ? ? ? b = b[nw:] ? ? ? ? ? n += nw ? ? ? ? case <-p.done: ? ? ? ? ? return n, p.writeCloseError() ? ? ? ? } ? ? ? } ? ? ? return n, nil ? ? }
讀寫都是利用兩個(gè)階段的select
來完成,第一個(gè)階段的select是判斷讀寫有沒有結(jié)束, 第二階段處理實(shí)際的讀寫.
Read
- 每次將讀的數(shù)量寫到讀信道
Write
- 先將緩沖寫到寫信道,再從讀信道中獲取讀字節(jié)數(shù),最后調(diào)整緩沖
- 如果緩沖太大,一次讀沒讀完,就將寫的過程多來幾遍,知道緩沖全部寫完
4.寫法
PipeWriter/PipeReader
對(duì)外暴露的關(guān)閉,其實(shí)只可以保留一個(gè)CloseWithError
, 但是為了方便客戶(調(diào)用者),還是拆成兩個(gè),其實(shí)可以做測試比較一下. 性能測試發(fā)現(xiàn)拆成兩個(gè)或?qū)懗梢粋€(gè)可選參函數(shù),性能上差別不大, 那這種寫法的主要作用是讓暴露的方法更加清晰易懂.
pipe.Write
中,for循環(huán)帶有once參數(shù),可以保證循環(huán)至少來一次, 算是do while的一種實(shí)現(xiàn).
5.總結(jié)
不管是PipeReader/PipeWriter,還是pipe,都對(duì)Reader/Writer有(部分)實(shí)現(xiàn).
另外還有一些細(xì)節(jié)沒有說道:讀寫錯(cuò)誤和EOF.
反思:本次閱讀是先理代碼后看文檔,才發(fā)現(xiàn)關(guān)于error部分沒有留心到, 后面還是先文檔后代碼,這樣效率會(huì)高一點(diǎn).
到此這篇關(guān)于Go語言io pipe源碼分析詳情的文章就介紹到這了,更多相關(guān)Go語言io pipe源碼分析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang Gin框架實(shí)現(xiàn)多種數(shù)據(jù)格式返回結(jié)果詳解
這篇文章主要介紹了Golang Gin框架實(shí)現(xiàn)多種數(shù)據(jù)格式返回結(jié)果,我們都知道,一個(gè)完整的請(qǐng)求包含請(qǐng)求和處理請(qǐng)求以及結(jié)果返回三個(gè)步驟,在服務(wù)器端對(duì)請(qǐng)求處理完成以后,會(huì)將結(jié)果返回給客戶端,在gin框架中,支持返回多種請(qǐng)求數(shù)據(jù)格式,下面我們一起來看看2023-05-05go語言 xorm框架 postgresql 的用法及詳細(xì)注解
這篇文章主要介紹了go語言 xorm框架 postgresql 的用法及詳細(xì)注解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12mac下golang安裝了windows編譯環(huán)境后編譯變慢
這篇文章主要介紹了mac下golang安裝了windows編譯環(huán)境后編譯變慢的處理方法,非常的簡單,有相同問題的小伙伴可以參考下。2015-04-04Go語言之io.ReadAtLeast函數(shù)的基本使用和原理解析
io.ReadAtLeast函數(shù)是Go語言標(biāo)準(zhǔn)庫提供的一個(gè)工具函數(shù),能夠從數(shù)據(jù)源讀取至少指定數(shù)量的字節(jié)數(shù)據(jù)到緩沖區(qū)中,這篇文章主要介紹了io.ReadAtLeast函數(shù)的相關(guān)知識(shí),需要的朋友可以參考下2023-07-07