網站首頁 編程語言 正文
pipe.go分析:
- 這個文件使用到了errors包,也是用到了sync庫.
- 文件說明:pipe是一個適配器,用于連接Reader和Writer.
1.結構分析
對外暴露的是一個構造函數和構造的兩個對象. 兩個對象分別暴露了方法,同時這兩個對象還有一個共同的底層對象. 實際上,這兩個對象暴露的方法是直接調用底層對象的, 那么核心還是在底層對象上,只是通過兩個對象和一個構造方法將底層對象的細節隱藏了.
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結構體中主要分兩塊:
- 讀寫信道
- 兩個無緩沖信道
- 一個互斥量(保護暴露的寫函數)
- 結束標識
- once保證done的關閉只執行一次
- done標志整個讀寫的結束
- 剩下兩個用于存儲讀寫錯誤
- PipeReader/PipeWriter的分析
3.PipeReader對外暴露的是讀/關閉
? ? 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對外暴露的是寫/關閉?
? ?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) ? ? }
他們的方法集都是指針接收者.具體方法的實現是通過pipe
的方法完成的. pipe的方法更加明確:讀/獲取讀錯誤/結束讀寫并設置讀錯誤; 寫/獲取寫錯誤/結束讀寫并設置寫錯誤.思路相當明確.
下面主要分析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 ? ? }
讀寫都是利用兩個階段的select
來完成,第一個階段的select是判斷讀寫有沒有結束, 第二階段處理實際的讀寫.
Read
- 每次將讀的數量寫到讀信道
Write
- 先將緩沖寫到寫信道,再從讀信道中獲取讀字節數,最后調整緩沖
- 如果緩沖太大,一次讀沒讀完,就將寫的過程多來幾遍,知道緩沖全部寫完
4.寫法
PipeWriter/PipeReader
對外暴露的關閉,其實只可以保留一個CloseWithError
, 但是為了方便客戶(調用者),還是拆成兩個,其實可以做測試比較一下. 性能測試發現拆成兩個或寫成一個可選參函數,性能上差別不大, 那這種寫法的主要作用是讓暴露的方法更加清晰易懂.
pipe.Write
中,for循環帶有once參數,可以保證循環至少來一次, 算是do while的一種實現.
5.總結
不管是PipeReader/PipeWriter,還是pipe,都對Reader/Writer有(部分)實現.
另外還有一些細節沒有說道:讀寫錯誤和EOF.
反思:本次閱讀是先理代碼后看文檔,才發現關于error部分沒有留心到, 后面還是先文檔后代碼,這樣效率會高一點.
原文鏈接:https://juejin.cn/post/7060406951619854367
相關推薦
- 2022-07-17 Android?studio實現簡易的計算器功能_Android
- 2022-08-10 C#中通過Command模式實現Redo/Undo方案_C#教程
- 2022-09-13 C++中的偽隨機數_C 語言
- 2022-07-13 python版jpeg合成pdf兩種方法
- 2022-07-15 Python中else怎么用?else的用法總結_python
- 2023-05-29 Python常見異常的處理方式淺析_python
- 2022-05-08 Python?sns.distplot()方法的使用方法_python
- 2022-10-11 React - 當輸入框獲取焦點時自動選中輸入框中的內容
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支