2011-09-23 47 views
13

我正在使用.NET 4.0 BlockingCollection来处理每个项目的队列,每个项目都需要由可能需要一秒时间处理每个项目的操作来处理。这个项目队列可以被不同的线程添加。多个消费者和查询C#BlockingCollection

我有几个关于这个 的问题a)允许多个消费者使用这个BlockingCollection?我注意到了GetConsumingEnumerable(),这似乎适用于单个消费者场景。拥有多个消费者的原因是,通过命名管道实例的处理一次最多可以处理这些项目中的三个,所以我认为我可以有三个消费者。

b)是否有方法检查一个项目是否在这个队列中,如果是,让调用者检查在项目被处理之前是否有一个项目被阻塞?

编辑:

基于乔恩斯基特的回答这里的一些示例代码使用GetConsumingEnumerable()说明作用于由单一生产填充的BlockingCollection多个消费者,与消费者:

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 

回答

10

多个消费者只需调用TakeTryTake同时 - 每个项目只能由单个消费者消费。

但是,我相信GetConsumingEnumerable也做你想做的。我相信如果每个调用者都调用它,每个调用者都会得到一个单独的消耗枚举值,这将再次确保每个项目只消耗一次。我不知道当队列变空时会发生什么 - 我不知道MoveNext()然后阻塞,或返回false。

我并没有真正按照你的第二个问题,但...

+0

对不起 - 它似乎在第二读一点含糊。所以,问题是我想能够确定一个项目是否在队列中进行处理(简单,因为我只需编写一个linq查询来检查它),所以我不会将重复项添加到队列中(并防止不必要的重复处理)。此队列是PDF书写器通过命名管道的输入,它将PDF写入共享位置。 – pkiddie

+0

现在,如果一个项目被请求已经在队列中(通过我写的HttpHandler说),我希望HttpHandler上的调用请求阻塞,直到该项目已经被处理,所以我可以保证任务已经完成,并且PDF文件存在于磁盘上,然后投入使用。 希望上下文有帮助! – pkiddie

+0

@pkiddie:你也不想知道该物品是否已经处理过? –

相关问题