using System;
using System.Threading;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace RingBufferTest
{
public class RingBuffer<T>
{
public long start = 0;
public long end = 0;
public T[] buffer;
public RingBuffer(int size)
{
buffer = new T[size + 1];
}
public bool Empty()
{
return start == end;
}
public bool Push(T data)
{
if (end >= start)
{
var freeLen = buffer.Length - (end - start);
if (freeLen <= 1)
{
return false;
}
var cutLen0 = buffer.Length - end;
if (cutLen0 >= 1)
{
buffer[end] = data;
++end;
}
else
{
buffer[0] = data;
end = 1;
}
}
else
{
var freeLen = start - end;
if (freeLen <= 1)
{
return false;
}
buffer[end] = data;
++end;
}
return true;
}
public T Pop()
{
T retObj = default;
if (end == start)
{
return retObj;
}
else if (end > start)
{
var usedLen = end - start;
if (usedLen < 1)
{
return retObj;
}
retObj = buffer[start];
++start;
return retObj;
}
else
{
var usedLen = buffer.Length - (start - end);
if (usedLen < 1)
{
return retObj;
}
var cutLen0 = buffer.Length - start;
if (cutLen0 >= 1)
{
retObj = buffer[start];
++start;
return retObj;
}
else
{
retObj = buffer[0];
start = 1;
return retObj;
}
}
}
}
public class RingBuffer1<T>
{
public long start = 0;
protected long _x0, _x1, _x2, _x3, _x4, _x5, _x6;
public long end = 0;
public T[] buffer;
public RingBuffer1(int size)
{
buffer = new T[size + 1];
}
public bool Empty()
{
return start == end;
}
public bool Push(T data)
{
if (end >= start)
{
var freeLen = buffer.Length - (end - start);
if (freeLen <= 1)
{
return false;
}
var cutLen0 = buffer.Length - end;
if (cutLen0 >= 1)
{
buffer[end] = data;
++end;
}
else
{
buffer[0] = data;
end = 1;
}
}
else
{
var freeLen = start - end;
if (freeLen <= 1)
{
return false;
}
buffer[end] = data;
++end;
}
return true;
}
public T Pop()
{
T retObj = default;
if (end == start)
{
return retObj;
}
else if (end > start)
{
var usedLen = end - start;
if (usedLen < 1)
{
return retObj;
}
retObj = buffer[start];
++start;
return retObj;
}
else
{
var usedLen = buffer.Length - (start - end);
if (usedLen < 1)
{
return retObj;
}
var cutLen0 = buffer.Length - start;
if (cutLen0 >= 1)
{
retObj = buffer[start];
++start;
return retObj;
}
else
{
retObj = buffer[0];
start = 1;
return retObj;
}
}
}
}
[StructLayout(LayoutKind.Explicit)]
public class ByteRingBuffer
{
[FieldOffset(0)]
public long start = 0;
[FieldOffset(64)]
public long end = 0;
[FieldOffset(128)]
public byte[] buffer;
public static string getMemory(object o)
{
GCHandle h = GCHandle.Alloc(o, GCHandleType.Pinned);
IntPtr addr = h.AddrOfPinnedObject();
return addr.ToString();
}
public ByteRingBuffer(int size)
{
buffer = new byte[size + 1];
}
public bool Empty()
{
return start == end;
}
public bool Push(byte data)
{
if (end >= start)
{
var freeLen = buffer.Length - (end - start);
if (freeLen <= 1)
{
return false;
}
var cutLen0 = buffer.Length - end;
if (cutLen0 >= 1)
{
buffer[end] = data;
++end;
}
else
{
buffer[0] = data;
end = 1;
}
}
else
{
var freeLen = start - end;
if (freeLen <= 1)
{
return false;
}
buffer[end] = data;
++end;
}
return true;
}
public byte Pop()
{
byte retObj = default;
if (end == start)
{
return retObj;
}
else if (end > start)
{
var usedLen = end - start;
if (usedLen < 1)
{
return retObj;
}
retObj = buffer[start];
++start;
return retObj;
}
else
{
var usedLen = buffer.Length - (start - end);
if (usedLen < 1)
{
return retObj;
}
var cutLen0 = buffer.Length - start;
if (cutLen0 >= 1)
{
retObj = buffer[start];
++start;
return retObj;
}
else
{
retObj = buffer[0];
start = 1;
return retObj;
}
}
}
}
class Program
{
const int RingBufferSize = 1024*1024*3;
const int LoopNum = 100 * 5;
static float st1 = 0.0f;
static float st2 = 0.0f;
static void testPushAndPop() {
float t1 = 0.0f;
float t2 = 0.0f;
//var rg = new RingBuffer<byte>(RingBufferSize);
//var rg = new RingBuffer1<byte>(RingBufferSize);
var rg = new ByteRingBuffer(RingBufferSize);
bool push = false;
bool pop = false;
var popThread = new Thread(() => {
Stopwatch st = new Stopwatch();
st.Start();
for (var i = 0; i < RingBufferSize; i++)
{
rg.Pop();
}
st.Stop();
t1 += st.ElapsedMilliseconds;
push = true;
});
var pushThread = new Thread(() => {
Stopwatch st = new Stopwatch();
st.Start();
for (var ii = 0; ii < RingBufferSize; ii++)
{
rg.Push(1);
}
st.Stop();
t2 += st.ElapsedMilliseconds;
pop = true;
});
pushThread.Start();
popThread.Start();
Thread.Sleep(70);
while (!pop && !push) {
Thread.Sleep(10);
}
st1 += t1;
st2 += t2;
Console.WriteLine("push avg time: " + t1);
Console.WriteLine("pop avg time: " + t2);
}
static void Main(string[] args)
{
for (var i = 0; i < LoopNum; i++) {
Console.WriteLine("current index {0}", i);
testPushAndPop();
}
Console.WriteLine("********************");
Console.WriteLine("push avg time: " + st1 / LoopNum);
Console.WriteLine("pop avg time: " + st2 / LoopNum);
Console.ReadKey(true);
}
}
}
一个线程读,一个线程写,每次一个读写一个字节。单次读写3M数据,循环500次。
三种写法,仅仅改变类内存布局。 内部函数尚未优化。
测试结果:
ringbuffer 耗时约80ms
ringbuffer1 耗时约60ms
byteringbuffer 耗时约40ms