2016-06-13 2 views
0

Для проекта, над которым мы работали, мы использовали параллельный словарь, который был прекрасен до появления новой спецификации, которая требовала сортировки словаря (она должна оставаться в том порядке, в котором она была добавлена, вроде как FIFO) ,Есть ли сопутствующий сортированный словарь или что-то подобное?

В настоящее время это то, что мы делаем, мы берем й количество (5 в данном случае) элементы из словаря:

private Dictionary<PriorityOfMessage, ConcurrentDictionary<Guid, PriorityMessage>> mQueuedMessages = new Dictionary<PriorityOfMessage, ConcurrentDictionary<Guid, PriorityMessage>>(); 


var messages = new List<KeyValuePair<Guid, PriorityMessage>>(); 
messages.AddRange(mQueuedMessages[priority].Take(5)); 

тогда мы делаем некоторые вещи с ним, и в конце концов, если все удастся, мы удалили их.

Однако, если что-то не удается, мы не удалим их и не попробуем позже. К сожалению, нет совпадающего сортированного словаря, но есть ли способы обеспечить сохранение сообщений в том порядке, в котором они добавлены?

Очень важно, что мы можем взять несколько объектов из списка/словаря, не удаляя их (или нам нужно будет добавить их на передний план позже).

+2

насчет '' ConcurrentQueue ? – Rahul

+0

Может быть, просто использовать замок? Какие требования к параллелизму у вас есть? Трудно переоценить блокировку, если критическая область мала. – usr

+0

@Rahul Мне нужно видеть больше, чем просто первое, в очереди вы можете видеть только первый объект в очереди, не удаляя его, если вы удаляете что-то, что вы не можете вернуть. – Vincent

ответ

1

Как часто вы принимаете в секунду?

.

это может быть в тысячу раз в секунду

1000 операций в секунду блокировки не являются абсолютно ничего. Это почти не будет времени.

мой коллега уже пытались использовать замки и списки, и он считал его слишком медленным

По всей вероятности, это означает, что заблокированный область была слишком большой. Моя догадка это пошло что-то вроде этого:

lock (...) { 
var item = TakeFromQueue(); 
Process(item); 
DeleteFromQueue(item); 
} 

Это не работает, потому что Process слишком медленно. Это должно быть:

lock (...) 
var item = TakeFromQueue(); 

Process(item); 

lock (...) 
DeleteFromQueue(item); 

У вас не будет никаких проблем с этим вообще.

Теперь вы можете выбрать любую структуру данных, которая вам нравится. Вы больше не связаны возможностями встроенных параллельных структур данных. Помимо выбора структуры данных, которая вам нравится, вы также можете выполнять любую операцию на ней, которая вам нравится, например, принимать атомы несколькими атомами.

Я не полностью понял ваши потребности, но похоже, что SortedList может идти в правильном направлении.

-1

Вы могли бы также пойти на другое решение (не тестировал его производительность мудрым):

public class ConcurrentIndexableQueue<T> { 
    private long tailIndex; 
    private long headIndex; 
    private readonly ConcurrentDictionary<long, T> dictionary; 

    public ConcurrentIndexableQueue() { 
     tailIndex = -1; 
     headIndex = 0; 
     dictionary = new ConcurrentDictionary<long, T>(); 
    } 

    public long Count { get { return tailIndex - headIndex + 1; } } 

    public bool IsEmpty { get { return Count == 0; } } 

    public void Enqueue(T item) { 
     var enqueuePosition = Interlocked.Increment(ref tailIndex); 
     dictionary.AddOrUpdate(enqueuePosition, k => item, (k, v) => item); 
    } 

    public T Peek(long index) { 
     T item; 

     return dictionary.TryGetValue(index, out item) ? 
      item : 
      default(T); 
    } 

    public long TryDequeue(out T item) { 
     if (headIndex > tailIndex) { 
      item = default(T); 
      return -1; 
     } 

     var dequeuePosition = Interlocked.Increment(ref headIndex) - 1; 

     dictionary.TryRemove(dequeuePosition, out item); 

     return dequeuePosition; 
    } 

    public List<T> GetSnapshot() { 
     List<T> snapshot = new List<T>(); 
     long snapshotTail = tailIndex; 
     long snapshotHead = headIndex; 

     for (long i = snapshotHead; i < snapshotTail; i++) { 
      T item; 

      if (TryDequeue(out item) >= 0) { 
       snapshot.Add(item); 
      } 
     } 

     return snapshot; 
    } 
} 
Смежные вопросы