What type of IProducerConsumerCollection to use for my task?

后端 未结 2 717
礼貌的吻别
礼貌的吻别 2020-12-17 05:08

I have exactly 100 Sensors each \"measuring\" own data. I have exactly one DataSender which should send information from \"sensors\". The most recent information sh

相关标签:
2条回答
  • 2020-12-17 05:47

    Instead of using another data structure, do another trick. The element in your collection cannot be replaced but you can, instead of storing the actual value, store a mini container. When you want to replace, you actually replace the value in the container, instead of replacing the container.

    class ElementFromQueue
    {
         public object SensorData;
    }
    
    ...
    
    ElementFromQueue elem = new ElementFromQueue();
    elem.SensorData = new object();
    ...
    queue.Add(elem); //Element is in queue now
    ...
    elem.SensorData = new object(); //Update the data, simulating replace
    

    Or just create a queue of indices that will point to a sensor number. When a value is popped, the latest sensor value is queried from another, update-able collection

    0 讨论(0)
  • 2020-12-17 05:57

    I think you should implement your own IProducerConsumerCollection<T>. That's why it's an interface: so that you could easily make your own.

    You could do it using Dictionary<K,V> and Queue<T> to make sure receiving the data is fair, i.e. if you have just one device that produces data very fast, you won't send data just from this one.

    public class DeviceDataQueue<TDevice, TData>
        : IProducerConsumerCollection<Tuple<TDevice, TData>>
    {
        private readonly object m_lockObject = new object();
        private readonly Dictionary<TDevice, TData> m_data
            = new Dictionary<TDevice, TData>();
        private readonly Queue<TDevice> m_queue = new Queue<TDevice>();
    
        //some obviously implemented methods elided, just make sure they are thread-safe
    
        public int Count { get { return m_queue.Count; } }
    
        public object SyncRoot { get { return m_lockObject; } }
    
        public bool IsSynchronized { get { return true; } }
    
        public bool TryAdd(Tuple<TDevice, TData> item)
        {
            var device = item.Item1;
            var data = item.Item2;
    
            lock (m_lockObject)
            {
                if (!m_data.ContainsKey(device))
                    m_queue.Enqueue(device);
    
                m_data[device] = data;
            }
    
            return true;
        }
    
        public bool TryTake(out Tuple<TDevice, TData> item)
        {
            lock (m_lockObject)
            {
                if (m_queue.Count == 0)
                {
                    item = null;
                    return false;
                }
    
                var device = m_queue.Dequeue();
                var data = m_data[device];
                m_data.Remove(device);
                item = Tuple.Create(device, data);
                return true;
            }
        }
    }
    

    When used along these lines:

    Queue = new BlockingCollection<Tuple<IDevice, Data>>(
        new DeviceDataQueue<IDevice, Data>());
    
    Device1 = new Device(1, TimeSpan.FromSeconds(3), Queue);
    Device2 = new Device(2, TimeSpan.FromSeconds(5), Queue);
    
    while (true)
    {
        var tuple = Queue.Take();
        var device = tuple.Item1;
        var data = tuple.Item2;
    
        Console.WriteLine("{0}: Device {1} produced data at {2}.",
            DateTime.Now, device.Id, data.Created);
    
        Thread.Sleep(TimeSpan.FromSeconds(2));
    }
    

    it produces the following output:

    30.4.2011 20:40:43: Device 1 produced data at 30.4.2011 20:40:43.
    30.4.2011 20:40:45: Device 2 produced data at 30.4.2011 20:40:44.
    30.4.2011 20:40:47: Device 1 produced data at 30.4.2011 20:40:47.
    30.4.2011 20:40:49: Device 2 produced data at 30.4.2011 20:40:49.
    30.4.2011 20:40:51: Device 1 produced data at 30.4.2011 20:40:51.
    30.4.2011 20:40:54: Device 2 produced data at 30.4.2011 20:40:54.
    
    0 讨论(0)
提交回复
热议问题