为什么缓冲区可以大幅度提高I/O性能

为什么缓冲区可以大幅度提高I/O性能

缓冲区的基本概念缓冲区是在内存中分配的一段空间,用于暂时存储数据。当数据从一个设备传送到另一个设备时,缓冲区可以用来平滑这种传输过程,使得数据的发送和接收更加高效。

为什么需要缓冲区背景:计算机磁盘是由一个个磁道构成,每次进行数据读写的时候,都需要通过磁头寻找到到合适的磁道,才能执行读写数据的操作,而这个过程需要耗费一定的时间,即寻道时间。

原理:当我们引入缓冲区后,可以将多次小量的数据写入操作合并为一次大量的写入操作,从而大大减少寻道时间和旋转延迟,提高数据的读写效率。

与缓存的区别:

缓存主要用于存储最近或最经常访问的数据,利用硬件的性能优势,加快数据的访问速度,例如redis缓存利用内存速度远远大于磁盘的优势。在计算机底层则有CPU缓存(L1、L2、L3);内存缓存DRAM Cache;磁盘缓存Disk Cache等,从磁盘到CPU的缓存空间越来越大,性能也越来越好,造价也越来越高

而缓冲区主要用于减少数据传输和磁盘的读写次数,提高数据的读写效率。

缓冲区类型

全缓冲:数据只有在缓冲区满时才会被实际写入或读取。

行缓冲:在文本输入的情况下,数据在遇到换行符时会被实际写入或读取。

无缓冲:每次数据写入或读取都会立即执行。

自行实现带缓冲的I/O用go代码作为演示:

1234567891011121314151617181920212223242526272829303132333435type BufferedFileWriter struct { buffer []byte bufferEndIndex int fout *os.File}func NewWriter(f *os.File, bufferSize int) *BufferedFileWriter { return &BufferedFileWriter{ buffer: make([]byte, bufferSize), bufferEndIndex: 0, fout: f, }}func (w *BufferedFileWriter) Write(p []byte) { if len(p) >= len(w.buffer) { w.flush() _, _ = w.fout.Write(p) } else { if w.bufferEndIndex+len(p) >= len(w.buffer) { w.flush() } copy(w.buffer[w.bufferEndIndex:], p) w.bufferEndIndex += len(p) }}func (w *BufferedFileWriter) flush() { _, _ = w.fout.Write(w.buffer[0:w.bufferEndIndex]) w.bufferEndIndex = 0}func (w *BufferedFileWriter) WriteString(s string) { w.Write([]byte(s))}

与直接写文件和标准库的bufio对比耗时代码:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970//直接写文件func WriteDirectly() { fout, err := os.OpenFile(outFile1, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666) if err != nil { HandleError(err) } defer func(fout *os.File) { if err := fout.Close(); err != nil { HandleError(err) } }(fout) for i := 0; i < 9999; i++ { if _, err := fout.WriteString(text + "\n"); err != nil { HandleError(err) } }}//带缓冲区写文件func WriteWithBuffer() { fout, err := os.OpenFile(outFile2, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666) if err != nil { HandleError(err) } defer func(fout *os.File) { if err := fout.Close(); err != nil { HandleError(err) } }(fout) // 定义较大的缓冲区减少写磁盘次数,空间换时间 writer := NewWriter(fout, 8*1024) defer writer.flush() for i := 0; i < 9999; i++ { writer.WriteString(text + "\n") }}// bufio写文件func WriteWithBufio() { fout, err := os.Create(outFile3) if err != nil { HandleError(err) } defer func(fout *os.File) { if err := fout.Close(); err != nil { HandleError(err) } }(fout) writer := bufio.NewWriter(fout) defer writer.Flush() for i := 0; i < 9999; i++ { if _, err := writer.WriteString(text + "\n"); err != nil { HandleError(err) } }}func TestBufferIO(t *testing.T) { t1 := time.Now() WriteDirectly() t2 := time.Now() WriteWithBuffer() t3 := time.Now() WriteWithBufio() t4 := time.Now() fmt.Printf("直接写文件耗时:%v, 自行实现带缓冲区写文件:%v, 使用go标准库bufio写文件耗时:%v", t2.Sub(t1), t3.Sub(t2), t4.Sub(t3))}

结果:可以看出,自行实现带缓冲区写文件比直接写文件要快很多,速度接近于使用go标准库的bufio。

相关推荐

佛山东方广场
365体育投注提款

佛山东方广场

📅 07-10 👁️ 1398
[国际足球]巴西公布世界杯名单 卡卡小罗无缘
365体育投注提款

[国际足球]巴西公布世界杯名单 卡卡小罗无缘

📅 07-02 👁️ 5927
广西北部湾钝缀锦蛤精巢发育、精子发生及超微结构研究
365提款一直在审核

广西北部湾钝缀锦蛤精巢发育、精子发生及超微结构研究

📅 07-17 👁️ 3938
如何改变移动套餐?教你3种方法,轻松搞定
365提款一直在审核

如何改变移动套餐?教你3种方法,轻松搞定

📅 07-15 👁️ 3458
微信小程序在哪里
365体育投注提款

微信小程序在哪里

📅 07-01 👁️ 9638
国乒公布澳门世界杯参赛名单,樊振东基于个人情况不参赛
怎么正确使用冰箱 使用冰箱技巧【详解】
365体育投注提款

怎么正确使用冰箱 使用冰箱技巧【详解】

📅 08-27 👁️ 1115
网络安全密匙是不是wifi密码 电脑连接wifi时提示输入安全密钥是什么意思
花肌粹面膜怎么样?价格多少?为什么不受欢迎?
365bet平台网址

花肌粹面膜怎么样?价格多少?为什么不受欢迎?

📅 08-28 👁️ 1260