Monibuca v5 实现零拷贝BufReader

背景

在开发高 IO 的程序都会面临一个问题,就是如何提供从网络层读取数据的性能。

直接读取

直接读取类似下面这种情况

b:= make(100)
io.ReadFull(conn,b)

优点是简单,而且延迟较低,可以立即获取到想要长度的数据。缺点也很明显,需要频繁 make,更关键的是需要频繁调用 syscall,造成 CPU 损耗。

使用 bufio.Reader

这个是标准库提供的,带缓冲的读取方式

reader:=bufio.NewReader(conn)
b:= make(100)
io.ReadFull(reader,b)

原理是一次读入 4096(默认)的数据到缓存中,减少多次 syscall 。然后再从缓存中读取需要的数据,不够再从网络测读取。

但是:

  • 没有解决需要 make 导致的 gc 问题
  • 增加了内存复制操作

 

基于 v5 内存分配器实现的零拷贝BufReader

v5 的内存分配器看这篇:《v5 中实现优雅内存分配器

基本原理:

  1. 从分配器里面获取一块内存作为缓存
  2. 一次读入一大块数据到缓存中
  3. 缓存中再读取需要的数据,并且可以手动控制回收部分内存

当音视频数据在 ringbuffer 中将要被覆盖的时候,就把对应的内存回收。其他临时的数据(比如长度、时间戳等),都可以在使用完后立即回收。

 

橘色的内存块是黄色的切片,因此不需要拷贝就能直接使用,在音视频数据的缓存过程中也保持碎片形式,不进行合并操作,在发送的时候使用 writev 批量发送就避免了内存复制。后续可以再结合更底层的网络 IO 库进行进一步的优化底层传输效率。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章