Использовать ConcurrentQueue в операторе Linq - PullRequest
3 голосов
/ 10 сентября 2011

Если у меня есть ConcurrentQueue, есть ли предпочтительный способ использовать его с помощью оператора Linq? У него нет метода удаления всех элементов в виде последовательности, и его перечислитель не удаляет элементы.

Я выполняю пакетное потребление, то есть периодически хочу обработать очередь и очистить ее, вместо того, чтобы обрабатывать ее до тех пор, пока она не станет пустой, и блокировать до тех пор, пока в очередь не будет помещено больше элементов. Кажется, что BlockingCollection не будет работать, потому что он будет блокироваться при достижении последнего элемента, и я хочу, чтобы этот поток делал другие вещи, например, очищал другие очереди.

static ConcurrentQueue<int> MyQueue = new ConcurrentQueue<int>();
void Main()
{
    MyQueue.Enqueue(1);MyQueue.Enqueue(2);MyQueue.Enqueue(3);MyQueue.Enqueue(4);MyQueue.Enqueue(5);

    var lst = MyQueue.ToLookup(x => x.SomeProperty);
    //queue still has all elements
    MyQueue.Dump("queue");  
}

На данный момент я сделал вспомогательный метод

static IEnumerable<T> ReadAndEmptyQueue<T>(this ConcurrentQueue<T> q)
{
    T item;
    while(q.TryDequeue(out item))
    {
        yield return item;
    }
}

var lk = MyQueue.ReadAndEmptyQueue().ToLookup(x => x.SomeProperty);
MyQueue.Dump(); //size is now zero

Есть ли лучший способ, или я делаю это правильно?

1 Ответ

3 голосов
/ 10 сентября 2011

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

Не похоже, что BlockingCollection будет работать, потому что он будет блокироваться при достижении последнего элемента, и я хочу, чтобы этот поток выполнял другие действия, например, очищал другие очереди.

Единственное, что я бы упомянул, - иногда, с точки зрения дизайна, проще просто запустить отдельный потребительский поток для каждой очереди. Если вы сделаете это, каждый BlockingCollection<T> может просто использовать GetConsumingEnumerable() и блокировать по мере необходимости, так как они будут в состоянии ожидания, когда очередь пуста.

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

...