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

これには Circular Buffer を使用します - this oneを含む多くの実装があり、そのうちの 1 つにスレッドセーフなラッパーを作成することは難しくありません。

スロットが 100 ほどしかない場合、キーによる検索はかなり効率的であり、挿入は非常に効率的です (古いアイテムが破棄され、新しいアイテムに置き換えられるため、再割り当てはありません)。

于 2013-06-29T08:34:06.960 に答える