如果您想要逐字节地从磁盘读取数据,与每次直接从磁盘读取每个字节相比,使用缓冲区IO技术,我们可以一次将一个数据块读入缓冲区,然后消费者可以以任何您想要的方式从缓冲区读取数据 。通过减少繁重的系统调用,性能将得到提高最近一年各大中小厂都在搞"优化",说到优化,目的还是"降本增效",降低成本,增加效益(效率) 。
技术层面,也有一些降本增效的常规操作 。
比如池化、io缓冲区技术
golang
C#
eg.
【Golang中降本增效的常规实践】池化技术
snnc.Pool
ObjectPool
前端切图仔,归入前端资源池,随用随取
字节数组缓冲区
bytes.Buffer
List
---
io缓冲区
bufio
BufferStream
适度超前,赛道埋伏
池化技术 sync.Poolsync.Pool位于标准库,该文件提供了对临时对象的重复使用能力,避免了频繁的gc,对并发协程是安全的 。
该文件只有三个控制点:
- • New: 默认的临时对象
- • Get:从池中哪一个临时对象
- • Put:放回池中,以重用
package mAInimport ("sync""testing")type Person struct {Age int}var (personPool = sync.Pool{New: func() interface{} {// 设置默认值return &Person{}},})func ExampleObjPool() {var p *Personfor i := 0; i < 1000; i++ {for j := 0; j < 1000; j++ {p = personPool.Get().(*Person)p.Age = i + 1personPool.Put(p)}}p = personPool.Get().(*Person)fmt.Println(p.Age)// output:1000}func BenchmarkWithoutPool(b *testing.B) {var p *Personb.ReportAllocs()b.ResetTimer()for i := 0; i < b.N; i++ {for j := 0; j < 1000; j++ {p = new(Person)// 每次均产生临时对象p.Age = 23}}}func BenchmarkWithPool(b *testing.B) {var p *Personb.ReportAllocs()b.ResetTimer()for i := 0; i < b.N; i++ {for j := 0; j < 1000; j++ {p = personPool.Get().(*Person)// 从池中复用对象p.Age = 23personPool.Put(p)// 放回以重用}}}
测试结果如下,sync.Pool[重用临时对象]的性能可见一斑 。文章插图
图片
bytes.Buffergolang很多方法内充斥了[]byte, 就连最常规的序列化/反序列化,返回值/参数都是[]byte, 但是slice是一个冷冰冰的数据结构,没有得心趁手的操作行为,还有很多陷阱 。
func Marshal(v any) ([]byte, error)func Unmarshal(data []byte, v any)
A bytes.Buffer is a variable-sized buffer of bytes with Read and Write methods.坦白讲bytes.Buffer并非底层优化机制,实际提供了一个友好操作slice的方式 。
下面的"abcd"字符串,先读取首字符、后面追加字符"e":
var b bytes.Bufferb.Write([]byte("abcd")) // 写入之后,自动扩容rdbuf := make([]byte, 1)_, err := b.Read(rdbuf) // 读取一个字节的数据,移动读off指针if err != nil {panic(err)}fmt.Println(b.String()) // 上面读取了一个字符,读off已经移动,现从读off位置转换为stringb.WriteByte('e')// 在尾部写字符fmt.Println(b.String())fmt.Printf("%d, %d n", b.Len(), b.Cap()) // Len方法返回还能读取的字符数量,Cap返回底层buf的容量//output:bcd bcde4, 64
文章插图
图片
io缓冲区 bufioPackage bufio implements buffered I/O. It wraps an io.Reader or io.Writer object, creating another object (Reader or Writer) that also implements the interface but provides buffering and some help for textual I/O.
文章插图
图片
首先我们需要知道当应用程序执行IO操作(从文件、网络和数据库读取或写入数据),它将触发底层的系统调用,从性能角度来看,这很繁重 。
缓冲IO是一种技术,用于在传递之前暂时积累IO操作的结果 。这种技术可以通过减少系统调用的次数来提高程序的速度 。
例如,如果您想要逐字节地从磁盘读取数据,与每次直接从磁盘读取每个字节相比,使用缓冲区IO技术,我们可以一次将一个数据块读入缓冲区,然后消费者可以以任何您想要的方式从缓冲区读取数据 。通过减少繁重的系统调用,性能将得到提高 。
推荐阅读
- golang反射实现原理
- Golang中如何判断两个Slice是否相等?
- 使用Golang构建一万+每秒处理请求的高性能系统
- 一文彻底弄明白Golang获取各种路径问题
- 带你使用Golang快速构建出命令行应用程序
- golang分离加载shellcode实现免杀