更正并发集合以存储定时非重复结构

时间:2013-06-29 06:51:37

标签: c# c#-4.0 collections concurrency

我正在为以下场景搜索正确的线程安全集合(并发集合):

我可能会从外部源请求生成GUID(因此它是唯一且非重复的)。我需要存储(比如最后100个请求)并检查是否传递了重复的GUID。由于某些限制,我可能不会将所有GUID保存超过100个。

现在的问题是,当在服务中使用此机制时,它必须绑定到100个项目,并且基于GUID进行搜索至关重要。

我决定使用ConcurrentDictionary但我怀疑这是一个很好的决定,因为我可以在使用整个100个插槽后更改密钥。我可能会找到一种很好的机制来在字典填满时替换最旧的请求。

非常感谢任何想法。

提供了一个代码段来显示我未完成的实现

public static ConcurrentDictionary<string, TimedProto> IncidentsCreated = new ConcurrentDictionary<string, TimedProto>(20, 100);

    private static bool AddTo_AddedIncidents(proto ReceivedIncident)
    {
        try
        {
            int OldestCounter = 0;
            DateTime OldestTime = DateTime.Now;

            if (IncidentsCreated.Count < 100)
            {
                TimedProto tp = new TimedProto();
                tp.IncidentProto = ReceivedIncident;
                tp.time = DateTime.Now;
                IncidentsCreated.AddOrUpdate(ReceivedIncident.IncidentGUID,  tp,
                    (s,i) => i);
                return true;
            }
            else //array is full, a replace oldest mechanism is required
            {

            }
            return true;
        }
        catch (Exception ex)
        {
            LogEvent("AddTo_AddedIncidents\n"+ex.ToString(), EventLogEntryType.Error);
            return false;
        }
    }


public struct proto
{
    public string IncidentGUID;
    //other variables
}

public struct TimedProto
{
    public proto IncidentProto;
    public DateTime time;
}

由于

2 个答案:

答案 0 :(得分:1)

试试这个:http://ayende.com/blog/162529/trivial-lru-cache-impl?key=02e8069c-62f8-4042-a7d2-d93806369824&utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+AyendeRahien+%28Ayende+%40+Rahien%29

由于您使用的粒度为15毫秒的DateTime,因此您的实现存在缺陷。这意味着如果流入量很大,您甚至可能会意外删除最近的guid。

public class LruCache<TKey, TValue>
{
    private readonly int _capacity;
    private readonly Stopwatch _stopwatch = Stopwatch.StartNew();

    class Reference<T> where T : struct
    {
   public T Value;
    }

    private class Node
    {
        public TValue Value;
        public volatile Reference<long> Ticks;
    }

    private readonly ConcurrentDictionary<TKey, Node> _nodes = new ConcurrentDictionary<TKey, Node>();

    public LruCache(int capacity)
    {
        Debug.Assert(capacity > 10);
        _capacity = capacity;
    }

    public void Set(TKey key, TValue value)
    {
        var node = new Node
        {
            Value = value,
            Ticks = new Reference<long> { Value = _stopwatch.ElapsedTicks }
        };

        _nodes.AddOrUpdate(key, node, (_, __) => node);
        if (_nodes.Count > _capacity)
        {
            foreach (var source in _nodes.OrderBy(x => x.Value.Ticks).Take(_nodes.Count / 10))
            {
                Node _;
                _nodes.TryRemove(source.Key, out _);
            }
        }
    }

    public bool TryGet(TKey key, out TValue value)
    {
        Node node;
        if (_nodes.TryGetValue(key, out node))
        {
            node.Ticks = new Reference<long> {Value = _stopwatch.ElapsedTicks};
            value = node.Value;
            return true;
        }

        value = default(TValue);
        return false;
    }
}

答案 1 :(得分:0)

我会使用循环缓冲区 - 有很多实现,包括this one,并为其中一个做一个线程安全的包装并不难。

只有100个左右的插槽,按键查找会相当有效,并且插入效率非常高(不会重新分配,因为旧项目被丢弃并被新项目替换)。