Circularbuffer学习笔记
请大家关注我的微博:@NormanLin_BadPixel坏像素
因为这是LandlordsCore作者3.0对TBuffer进行的修改,如果有兴趣的话,大家可以去看看我之前写的TBuffer学习笔记,里面可能会比较详细。 而且这篇里如果有TBuffer里讲过的,我会一笔带过。
public int ChunkSize = 8192;
private readonly Queue<byte[]> bufferQueue = new Queue<byte[]>();
private readonly Queue<byte[]> bufferCache = new Queue<byte[]>();
public int LastIndex { get; set; }
public int FirstIndex { get; set; }
private byte[] lastBuffer;
跟TBuffer有一些类似的地方,也有不同的。最明显的,就是取消了LinkedList的使用,看来作者发现了我们其实并没有用到LinkedList的特征,快速的插入。因为我们一般只会取出缓冲区的首位,和往末位插入新的数据,应对这样的需求,Queue就已经符合要求了。Queue是一个先进先出的队列,不用我多说了吧?
至于lastBuffer这个变量,我们从Queue当中获取首位数据很方便,但是没法获取末位的数据,所以这里特意分配一块内存给末位的数据区块,方便操作。
至于bufferCache是干什么的?我们结合后面的AddLast来看看。
public void AddLast()
{
byte[] buffer;
if (this.bufferCache.Count > 0)
{
buffer = this.bufferCache.Dequeue();
}
else
{
buffer = new byte[ChunkSize];
}
this.bufferQueue.Enqueue(buffer);
this.lastBuffer = buffer;
}
我们发现,如果我们要向bufferQueue中添加新的数据区块的时候,会先判断bufferQueue中有没有数据区块,如果有的话,则从bufferQueue当中取出一个数据区块进队bufferQueue。其实这是一个类似对象池的设计,为了优化内存的调用,避免多次new一片新的内存。而bufferCache中的数据区块,应该就是从bufferQueue当中出队并已经没有用的数据区块了。在TBuffer当中我们是直接释让这部分内存垃圾回收了,而这里,我们自己对它们进行了回收,并且进行再利用。牛逼。
public void RemoveFirst()
{
this.bufferCache.Enqueue(bufferQueue.Dequeue());
}
这段就是对数据区块的回收了,不用当心我们没有对进队的数据区块进行“清空”,因为我们以LastIndex自己控制游标位置,这些旧的数据会被新的数据所覆盖的。
获取首位数据区块跟末尾区块的方法我就不说了,聪明的大家一眼就能看懂。这里顺便提一下,Queue.Peek() 方法只会返回队列的第一位但是并不会让它从队列中移除。Dequeue才会移除。
/// <summary>
/// 从stream流写到CircularBuffer中
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
public async Task<int> WriteAsync(Stream stream)
作者的注释很详细了。从stream流写到CircularBuffer中。我们发现,新的3.0代码在这块运用了Stream。大家可以了解一下。就是文件读写的数据流。
Stream.ReadAsync : 从当前流异步读取字节序列,并将流中的位置提升读取的字节数。
public override int Read(byte[] buffer, int offset, int count)
这段代码,跟TBuffer里面的RecvFrom(byte[] buffer) 方法的作用是一样的,从这个缓冲区中获取数据。不过这里多了两个参数,offset跟cout,调用更加灵活了。
public void Write(byte[] buffer)
这段代码,跟TBuffer里面的SendTo(byte[] buffer) 是一样的,往缓冲区里写入新的数据,带过。
除此之外,这里也提供了有offset跟count参数的写入方法
public override void Write(byte[] buffer, int offset, int count)
不过这里的offset指的是buffer的offset。
注意的是,这些带offset跟count的Read和Write都是重写的方法。
并且,重写了一些方法,让CanRead跟CanWrite始终返回true,而CanSeek始终返回false。
结束语
就是因为程序员的追求,才让代码越来越难看,也越来越优雅。————Norman林