Несколько потребителей и запросы C # BlockingCollection - PullRequest
16 голосов
/ 23 сентября 2011

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

У меня есть пара вопросов относительно этого: а) разрешить нескольким потребителям работать с этой коллекцией BlockingCollection?Я заметил GetConsumingEnumerable (), который, кажется, применим для сценариев с одним потребителем.Причиной наличия нескольких потребителей является то, что обработка через именованный экземпляр канала может обрабатывать до трех из этих элементов одновременно, поэтому я подумал, что у меня может быть три потребителя.

b) Есть ли способпроверки, находится ли элемент в этой очереди, и, если да, получение вызывающей стороны, которая проверяет, есть ли элемент для блокировки, пока элемент не был обработан?

РЕДАКТИРОВАТЬ:

На основе ответа Джона Скита приведен пример кода для иллюстрации нескольких потребителей, действующих на BlockingCollection, заполненных одним производителем, с потребителями, использующими GetConsumingEnumerable():

static BlockingCollection<string> coll = new BlockingCollection<string>();

static void Consume()
{
    foreach (var i in coll.GetConsumingEnumerable())
    {
        Console.WriteLine(String.Format("Thread {0} Consuming: {1}",  Thread.CurrentThread.ManagedThreadId, i));
        Thread.Sleep(1000);
    }
}

static void Main(string[] args)
{
    int item = 0;

    Task.Factory.StartNew(() =>
    {
        while (true)
        {
            coll.Add(string.Format("Item {0}", item++));
            Thread.Sleep(500);
        }
    });

    for (int i = 0; i < 2; i++)
    {
        Task.Factory.StartNew(() => Consume());
    }

    while (true) ;
}

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

Thread 4 Consuming: Item 0
Thread 5 Consuming: Item 1
Thread 4 Consuming: Item 2
Thread 5 Consuming: Item 3
Thread 4 Consuming: Item 4

1 Ответ

11 голосов
/ 23 сентября 2011

Несколько потребителей могут просто позвонить Take или TryTake одновременно - каждый предмет будет потребляться только одним потребителем.

Однако я верю, что GetConsumingEnumerable будет также делать то, что вы хотите. Я полагаю, что если каждый вызывающий вызов вызывает это, каждый получит отдельное перечисляемое потребление, которое снова будет гарантировать, что каждый элемент потребляется только один раз. Я не уверен, что произойдет, когда очередь станет пустой - я не знаю, блокирует ли MoveNext() затем или возвращает false.

Я действительно не следил за твоим вторым вопросом, хотя ...

...