2011-09-23 95 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:你也不想知道該物品是否已經處理過? –

相關問題