2

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

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

现在的问题是,当在服务中使用这种机制时,它必须绑定到 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;
}

谢谢

4

2 回答 2

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+拉希恩%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;
    }
}
于 2013-06-29T07:11:53.353 回答
0

我会为此使用一个循环缓冲区——周围有很多实现,包括这个,并且为其中一个实现线程安全的包装器并不难。

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

于 2013-06-29T08:34:06.960 回答