在开发高 IO 的程序都会面临一个问题,就是如何提供从网络层读取数据的性能。
直接读取类似下面这种情况
b:= make(100)
io.ReadFull(conn,b)
优点是简单,而且延迟较低,可以立即获取到想要长度的数据。 缺点也很明显,需要频繁 make,更关键的是需要频繁调用 syscall,造成 CPU 损耗。
这个是标准库提供的,带缓冲的读取方式
reader:=bufio.NewReader(conn)
b:= make(100)
io.ReadFull(reader,b)
原理是一次读入 4096(默认)的数据到缓存中,减少多次 syscall 。然后再从缓存中读取需要的数据,不够再从网络测读取。
但是:
v5 的内存分配器看这篇:《
》
基本原理:
1. 从分配器里面获取一块内存作为缓存
2. 一次读入一大块数据到缓存中
3. 缓存中再读取需要的数据,并且可以手动控制回收部分内存
当音视频数据在 ringbuffer 中将要被覆盖的时候,就把对应的内存回收。其他临时的数据(比如长度、时间戳等),都可以在使用完后立即回收。
橘色的内存块是黄色的切片,因此不需要拷贝就能直接使用,在音视频数据的缓存过程中也保持碎片形式,不进行合并操作,在发送的时候使用 writev 批量发送就避免了内存复制。后续可以再结合更底层的网络 IO 库进行进一步的优化底层传输效率。
下面是和 bufio 的 Reader 做一个性能对比: