159 votes

Fixe la taille de la file d'attente qui retire automatiquement les anciennes valeurs sur les nouveaux enques

Je suis à l'aide d' ConcurrentQueue pour une structure de données partagées dont le but est de tenir les N derniers objets du passé (l'histoire).

Supposons que nous avons un navigateur et nous voulons avoir le 100 derniers parcouru Url. Je veux une file d'attente qui automatiquement drop (file d'attente) la plus ancienne (la première) entrée sur nouvelle entrée d'insertion (mise en file d'attente) lorsque la capacité est pleine (100 adresses dans l'histoire).

Comment puis-je utiliser System.Collections ?

131voto

Richard Schneider Points 16054

Je voudrais écrire une classe wrapper sur la mise en File d'attente serait de vérifier le Comte, puis file d'attente lorsque le nombre dépasse la limite.

 public class FixedSizedQueue<T>
 {
     ConcurrentQueue<T> q = new ConcurrentQueue<T>();

     public int Limit { get; set; }
     public void Enqueue(T obj)
     {
        q.Enqueue(obj);
        lock (this)
        {
           T overflow;
           while (q.Count > Limit && q.TryDequeue(out overflow)) ;
        }
     }
 }

114voto

daveL Points 1509

J'irais pour une variante légère... étendre ConcurrentQueue de manière à être capable d'utiliser les extensions Linq sur FixedSizeQueue

public class FixedSizedQueue<T> : ConcurrentQueue<T>
{
    public int Size { get; private set; }

    public FixedSizedQueue(int size)
    {
        Size = size;
    }

    public new void Enqueue(T obj)
    {
        base.Enqueue(obj);
        lock (this)
        {
            while (base.Count > Size)
            {
                T outObj;
                base.TryDequeue(out outObj);
            }
        }
    }
}

34voto

Tod Thomson Points 1145

Pour toute personne qui estime utile, voici un peu de code de travail basé sur Richard Schneider réponse ci-dessus:

public class FixedSizedQueue<T>
{
    readonly ConcurrentQueue<T> queue = new ConcurrentQueue<T>();

    public int Size { get; private set; }

    public FixedSizedQueue(int size)
    {
        Size = size;
    }

    public void Enqueue(T obj)
    {
        queue.Enqueue(obj);
        lock (this)
        {
            while (queue.Count > Size)
            {
                T outObj;
                queue.TryDequeue(out outObj);
            }
        }
    }
}

16voto

Juliet Points 40758

Pour ce que sa vaut la peine, voici un léger tampon circulaire avec certaines méthodes marqué pour la sécurité et l'utilisation non sécuritaire.

public class CircularBuffer<T> : IEnumerable<T>
{
    readonly int size;
    readonly object locker;

    int count;
    int head;
    int rear;
    T[] values;

    public CircularBuffer(int max)
    {
        this.size = max;
        locker = new object();
        count = 0;
        head = 0;
        rear = 0;
        values = new T[size];
    }

    static int Incr(int index, int size)
    {
        return (index + 1) % size;
    }

    private void UnsafeEnsureQueueNotEmpty()
    {
        if (count == 0)
            throw new Exception("Empty queue");
    }

    public int Size { get { return size; } }
    public object SyncRoot { get { return locker; } }

    #region Count

    public int Count { get { return UnsafeCount; } }
    public int SafeCount { get { lock (locker) { return UnsafeCount; } } }
    public int UnsafeCount { get { return count; } }

    #endregion

    #region Enqueue

    public void Enqueue(T obj)
    {
        UnsafeEnqueue(obj);
    }

    public void SafeEnqueue(T obj)
    {
        lock (locker) { UnsafeEnqueue(obj); }
    }

    public void UnsafeEnqueue(T obj)
    {
        values[rear] = obj;

        if (Count == Size)
            head = Incr(head, Size);
        rear = Incr(rear, Size);
        count = Math.Min(count + 1, Size);
    }

    #endregion

    #region Dequeue

    public T Dequeue()
    {
        return UnsafeDequeue();
    }

    public T SafeDequeue()
    {
        lock (locker) { return UnsafeDequeue(); }
    }

    public T UnsafeDequeue()
    {
        UnsafeEnsureQueueNotEmpty();

        T res = values[head];
        values[head] = default(T);
        head = Incr(head, Size);
        count--;

        return res;
    }

    #endregion

    #region Peek

    public T Peek()
    {
        return UnsafePeek();
    }

    public T SafePeek()
    {
        lock (locker) { return UnsafePeek(); }
    }

    public T UnsafePeek()
    {
        UnsafeEnsureQueueNotEmpty();

        return values[head];
    }

    #endregion


    #region GetEnumerator

    public IEnumerator<T> GetEnumerator()
    {
        return UnsafeGetEnumerator();
    }

    public IEnumerator<T> SafeGetEnumerator()
    {
        lock (locker)
        {
            List<T> res = new List<T>(count);
            var enumerator = UnsafeGetEnumerator();
            while (enumerator.MoveNext())
                res.Add(enumerator.Current);
            return res.GetEnumerator();
        }
    }

    public IEnumerator<T> UnsafeGetEnumerator()
    {
        int index = head;
        for (int i = 0; i < count; i++)
        {
            yield return values[index];
            index = Incr(index, size);
        }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }

    #endregion
}

J'aime utiliser l' Foo()/SafeFoo()/UnsafeFoo() convention:

  • Foo méthodes s'appellent UnsafeFoo comme valeur par défaut.
  • UnsafeFoo méthodes de modifier l'état librement, sans une serrure, ne devrait en appeler d'autres utilisent des méthodes.
  • SafeFoo méthodes s'appellent UnsafeFoo méthodes à l'intérieur d'une serrure.

C'est un peu verbeux, mais il fait des erreurs évidentes, comme d'appeler des méthodes dangereuses à l'extérieur d'un verrouillage dans une méthode qui est censé être thread-safe, de plus en plus apparente.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X