C# Ringbuffer 实现+cacheline不同写法性能测试

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值