Go语言io pipe源码分析详情
作者:zwf193071 发布时间:2024-01-31 00:21:46
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
猜你喜欢
- 这个项目的名称与其叫做万能的XML不如叫做自动构建网站,根据一份XML文件,生成对应目录结构的网站,不过只有html还是太过于简单了,如果要
- 清空服务器缓存asp代码: <%Call RemoveAllCache()Sub RemoveAllCa
- 前言 相信很多时候大家都会用到虚拟环境,他具有可以让你快速切换不同的python版本,
- ALTER TABLE将表更改为当前字符集。如果在执行ALTER TABLE操作期间遇到重复键错误,原因在于新的字符集将2个键映射到了相同值
- 本文实例为大家分享了Golang实现断点续传的具体代码,供大家参考,具体内容如下1、将文件pic_src.jpg复制到pic_des.jpg
- date("yyyyMMdd",time()) date() 函数功能:用于格式化时间,返回一个字符串。&nb
- 1、灵活运用样式熟悉网页设计的网友就知道,调用Style的方法很多,我们可以单击鼠标右键选择Custon Style来调用Style标准,也
- NTP(Network Time Protocol)是由美国德拉瓦大学的David L. Mills教授于1985年提出,设计用来在Inte
- asp之家注:学习asp网页编程的朋友一定用过ACCESS数据库,access的简单方便,大大降低了asp初学者学习asp的门槛,对于学习a
- 面对不断成长的用户,跟随用户的脚步齐步向前,做引起共鸣的改变,去除低龄化的设计,用成熟稳重的心态面对用户。QQBanner自2006 年推出
- 这篇文章记录一个采样器都随机地从原始的数据集中抽样数据。抽样数据采用permutation。 生成任意一个下标重排,从而利用下标来提取dat
- 一、前言CRITIC权重法是一种比熵权法和标准离差法更好的客观赋权法:它是基于评价指标的对比强度和指标之间的冲突性来综合衡量指标的客观权重。
- 乱码问题破解压缩包时候会存在中文乱码问题!1:直接使用Everything搜索出要修改的库文件 zipfile.py ,并用notepad+
- 具体代码如下所示:from operator import itemgetter #itemgetter用来去dict中的key,省去了使用
- 模块介绍Python提供了importlib包作为标准库的一部分。目的就是提供Python中import语句的实现(以及__import__
- 目录一、为什么使用 .gitignore ?二、使用规则2.1 注释2.2 忽略文件(1)忽略文件和目录(2)仅忽略文件2.3 忽略目录2.
- Python进程池是Python标准库中multiprocessing模块提供的一种用于管理进程的方式。它可以使Python程序以并行的方式
- 安装Tornado省事点可以直接用grequests库,下面用的是tornado的异步client。 异步用到了tornado,根据官方文档
- 在许多情况下,对外键使用更复杂的逻辑表达式是非常有用的。 此外,在某些情况下能够在索引视图创建约束也将非常实用。 我将举例说明,同时我希望针
- 读取一个已经保存了的字典f = open('dict_th','r')a = f.read()dict_hi