Go語(yǔ)言io?pipe源碼分析詳情
pipe.go分析:
- 這個(gè)文件使用到了errors包,也是用到了sync庫(kù).
- 文件說(shuō)明: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ì)象上,只是通過(guò)兩個(gè)對(duì)象和一個(gè)構(gòu)造方法將底層對(duì)象的細(xì)節(jié)隱藏了.
2.pipe sruct分析
pipe的方法不多,新的寫(xiě)法卻不少.
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的原子讀寫(xiě).
? 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)體中主要分兩塊:
- 讀寫(xiě)信道
- 兩個(gè)無(wú)緩沖信道
- 一個(gè)互斥量(保護(hù)暴露的寫(xiě)函數(shù))
- 結(jié)束標(biāo)識(shí)
- once保證done的關(guān)閉只執(zhí)行一次
- done標(biāo)志整個(gè)讀寫(xiě)的結(jié)束
- 剩下兩個(gè)用于存儲(chǔ)讀寫(xiě)錯(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ì)外暴露的是寫(xiě)/關(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)是通過(guò)pipe的方法完成的. pipe的方法更加明確:讀/獲取讀錯(cuò)誤/結(jié)束讀寫(xiě)并設(shè)置讀錯(cuò)誤; 寫(xiě)/獲取寫(xiě)錯(cuò)誤/結(jié)束讀寫(xiě)并設(shè)置寫(xiě)錯(cuò)誤.思路相當(dāng)明確.
下面主要分析pipe的讀寫(xiě)
? 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
? ? }讀寫(xiě)都是利用兩個(gè)階段的select來(lái)完成,第一個(gè)階段的select是判斷讀寫(xiě)有沒(méi)有結(jié)束, 第二階段處理實(shí)際的讀寫(xiě).
Read
- 每次將讀的數(shù)量寫(xiě)到讀信道
Write
- 先將緩沖寫(xiě)到寫(xiě)信道,再?gòu)淖x信道中獲取讀字節(jié)數(shù),最后調(diào)整緩沖
- 如果緩沖太大,一次讀沒(méi)讀完,就將寫(xiě)的過(guò)程多來(lái)幾遍,知道緩沖全部寫(xiě)完
4.寫(xiě)法
PipeWriter/PipeReader對(duì)外暴露的關(guān)閉,其實(shí)只可以保留一個(gè)CloseWithError, 但是為了方便客戶(hù)(調(diào)用者),還是拆成兩個(gè),其實(shí)可以做測(cè)試比較一下. 性能測(cè)試發(fā)現(xiàn)拆成兩個(gè)或?qū)懗梢粋€(gè)可選參函數(shù),性能上差別不大, 那這種寫(xiě)法的主要作用是讓暴露的方法更加清晰易懂.
pipe.Write中,for循環(huán)帶有once參數(shù),可以保證循環(huán)至少來(lái)一次, 算是do while的一種實(shí)現(xiàn).
5.總結(jié)
不管是PipeReader/PipeWriter,還是pipe,都對(duì)Reader/Writer有(部分)實(shí)現(xiàn).
另外還有一些細(xì)節(jié)沒(méi)有說(shuō)道:讀寫(xiě)錯(cuò)誤和EOF.
反思:本次閱讀是先理代碼后看文檔,才發(fā)現(xiàn)關(guān)于error部分沒(méi)有留心到, 后面還是先文檔后代碼,這樣效率會(huì)高一點(diǎn).
到此這篇關(guān)于Go語(yǔ)言io pipe源碼分析詳情的文章就介紹到這了,更多相關(guān)Go語(yǔ)言io pipe源碼分析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang操作DuckDB實(shí)戰(zhàn)案例分享
DuckDB是一個(gè)嵌入式SQL數(shù)據(jù)庫(kù)引擎,它與眾所周知的SQLite非常相似,但它是為olap風(fēng)格的工作負(fù)載設(shè)計(jì)的,DuckDB支持各種數(shù)據(jù)類(lèi)型和SQL特性,憑借其在以?xún)?nèi)存為中心的環(huán)境中處理高速分析的能力,它迅速受到數(shù)據(jù)科學(xué)家和分析師的歡迎,在這篇博文中,我們將探索在Go中使用DuckDB2025-01-01
Go語(yǔ)言中兩個(gè)比較流行的緩存庫(kù)使用示例
緩存是計(jì)算機(jī)科學(xué)中的一個(gè)重要概念,設(shè)想某個(gè)組件需要訪問(wèn)外部資源,它向外部源請(qǐng)求資源,接收并使用資源,這些步驟都需要花費(fèi)時(shí)間,下面這篇文章主要給大家介紹了關(guān)于Go語(yǔ)言中兩個(gè)比較流行的緩存庫(kù)使用的相關(guān)資料,需要的朋友可以參考下2024-04-04
Go語(yǔ)言服務(wù)器開(kāi)發(fā)實(shí)現(xiàn)最簡(jiǎn)單HTTP的GET與POST接口
這篇文章主要介紹了Go語(yǔ)言服務(wù)器開(kāi)發(fā)實(shí)現(xiàn)最簡(jiǎn)單HTTP的GET與POST接口,實(shí)例分析了Go語(yǔ)言http包的使用技巧,需要的朋友可以參考下2015-02-02
Golang 協(xié)程配合管道的實(shí)現(xiàn)示例
本文主要介紹了Golang協(xié)程配合管道的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-01-01
GO常見(jiàn)的錯(cuò)誤99%程序員會(huì)遇到(解決方法)
這篇文章主要介紹了GO常見(jiàn)的錯(cuò)誤99%程序員會(huì)遇到,本文給出了解決方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01
Go操作Kafka的實(shí)現(xiàn)示例(kafka-go)
本文介紹了使用kafka-go庫(kù)在Go語(yǔ)言中與Kafka進(jìn)行交互,涵蓋了kafka-go的安裝、API使用、消息發(fā)送與消費(fèi)方法,以及如何通過(guò)DockerCompose快速搭建Kafka環(huán)境,文章還比較了其他兩個(gè)常用的Kafka客戶(hù)端庫(kù),感興趣的可以了解一下2024-10-10

