TransWikia.com

C# Performance in a CircularBuffer architecture in size and time

Code Review Asked on October 27, 2021

I need to speed up a circular buffer that has space and time requirements.

Each cell in the circular buffer represents a list of N elements to be sent. The shipment takes place if the list reaches N elements, or if the elapsed time exceeds X ms.

At the moment I have found this solution, but I am quite sure it is not the best possible to achieve my goal. I would like to understand if there are improvements for architecture.

public class RingBuffer<T> : IDisposable
{
    protected class TimerArray
    {
        private Timer _timer;
        private Int32 _index;
        private RingBuffer<T> _ring;

        public TimerArray(RingBuffer<T> ring, Int32 index)
        {
            _index = index;
            _ring = ring;
            _timer = new Timer(t => { ring.Send(_index); }, null, ring.TimerPeriod, ring.TimerPeriod);
        }

        public Boolean TimerReset()
        {
            return _timer.Change(_ring.TimerPeriod, _ring.TimerPeriod);
        }
    }

    protected Object _locker = new Object();
    protected ConcurrentQueue<T>[] _buffers;
    protected TimerArray[] _timer;
    protected Int64 current = 0;

    public Int32 RingDimension { get; set; }
    public Int32 SendSize { get; set; }
    public Int32 TimerPeriod { get; set; }
    public ISender Sender { get; set; }

    public Int64 BufferSize { get; set; }

    public RingBuffer(ISender sender, Int32 size, Int32 msTimer)
    {
        RingDimension = 10;
        Init(sender, size, msTimer);
    }

    public RingBuffer(ISender sender, Int32 dimension, Int32 size, Int32 msTimer)
    {
        RingDimension = dimension;
        Init(sender, size, msTimer);
    }

    protected void Init(ISender sender, Int32 size, Int32 msTimer)
    {
        _buffers = new ConcurrentQueue<T>[RingDimension];

        Sender = sender;
        SendSize = size == 0 ? -1 : size;
        TimerPeriod = msTimer;

        for (int i = 0; i < RingDimension; i++)
            _buffers[i] = new ConcurrentQueue<T>();

        if (TimerPeriod > 0)
        {
            _timer = new TimerArray[RingDimension];
            for (int i = 0; i < RingDimension; i++)
                _timer[i] = new TimerArray(this, i);
        }
    }

    public void Enqueue(T item)
    {
        lock (_locker)
        {
            if (!Object.ReferenceEquals(item, null))
                _buffers[current].Enqueue(item);
        }

        if (_buffers[current].Count >= SendSize)
        {
            lock (_locker)
            {
                if (_buffers[current].Count >= SendSize)
                {
                    var previous = Interlocked.Exchange(ref current, (current + 1) % RingDimension);
                    if (TimerPeriod > 0)
                        _timer[previous].TimerReset();

                    BufferSize += Sender.Enqueue(_buffers[previous].ToList());
                    _buffers[previous] = new ConcurrentQueue<T>();
                }
            }
        }
    }

    protected void Send(Int64 index)
    {
        if (_buffers[index].Count > 0)
        {
            lock (_locker)
            {
                if (_buffers[index].Count > 0)
                {
                    BufferSize += Sender.Enqueue(_buffers[index].ToList());
                    _buffers[index] = new ConcurrentQueue<T>();
                }
            }
        }
    }

    public virtual void Dispose()
    {
    }
}

Enqueue method is called by program anytime that a message is ready, check the list dimension and send it when list is full.

Send method is called by a Timer array that set a boundry limit for message latency.

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP