多个使用者和查询C#BlockingCollection

多个使用者和查询C#BlockingCollection,c#,.net,c#-4.0,C#,.net,C# 4.0,我正在使用.NET 4.0 BlockingCollection来处理一个项目队列,每个项目都需要由一个操作处理,处理每个项目可能需要一秒钟的时间。此项目队列可以由不同的线程添加到 关于这一点,我有几个问题 a) 允许多个消费者使用此BlockingCollection?我注意到GetConsumingEnumerable(),它似乎适用于单消费者场景。有多个使用者的原因是,通过一个命名管道实例进行处理,一次最多可以处理其中的三个项目,因此我认为可以有三个使用者 b) 是否有一种方法可以检查项目

我正在使用.NET 4.0 BlockingCollection来处理一个项目队列,每个项目都需要由一个操作处理,处理每个项目可能需要一秒钟的时间。此项目队列可以由不同的线程添加到

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

b) 是否有一种方法可以检查项目是否在此队列中,如果是,则让调用者检查是否有要阻止的项目,直到项目被处理为止

编辑:

根据Jon Skeet的回答,这里有一些示例代码来说明多个消费者对单个生产者填充的BlockingCollection的行为,消费者使用
GetConsumingEnumerable()


多个消费者可以同时调用
Take
TryTake
——每个商品仅由一个消费者消费

然而,我相信
getconsumineGenumerable
也能满足您的需求。我相信,如果每个调用方调用该函数,每个调用方都将得到一个单独的消费枚举,这将再次确保每个项只消费一次。我不确定队列变空时会发生什么情况-我不知道
MoveNext()
是阻塞还是返回false


我没有真正理解你的第二个问题,但是…

GetConsuminagenumerable
实际上可以同时从多个消费者那里调用;仅当集合标记为已完成时,可枚举项才完成。每件物品只消费一次


getconsumineGenumerable
是:


再加上一点取消/清理逻辑。

抱歉-二读时似乎有点模糊。所以,问题是我希望能够确定一个项目是否在队列中进行处理(很简单,因为我可以编写一个linq查询来检查这一点),这样我就不会向队列中添加重复的项目(并防止不必要的重复处理)。此队列是通过命名管道向PDF编写器发送的输入,命名管道将PDF写入共享位置。现在,如果请求的项目已经在队列中(例如由我编写的HttpHandler),我希望HttpHandler上的调用请求被阻止,直到该项目被处理,这样我可以保证任务已完成,在提供PDF文件之前,它已经存在于磁盘上。希望上下文有帮助@PKIDIE:你难道不想知道这个项目是否也已经被处理了吗?是的,所以我要做的是在将代表它的项目添加到队列之前检查磁盘上是否存在PDF,如果有,就提供它exists@pkiddie:我明白了。您的处理部件能否以原子方式尝试创建该文件?这样一来,同一个项目是否多次出现在队列中就无关紧要了——只有一件事会尝试对其进行处理,因为在此之后,处理器可以说“它要么已经完成,要么正在进行”。当使用
GetConsumingEnumerable
时,生产者调用
CompleteAdding()
以便消费者知道何时停止。
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
while (!IsCompleted)
{
  if (TryTake(out var item, Timeout.Infinite))
    yield return item;
}