2010-08-17 54 views
9

嘿,我想在C#中爲異步服務器實現ConcurrentQueue。一旦收到完整的消息,項目正在排隊。爲了使消息出隊,我使用少量線程來完成出隊和服務請求的工作。由於顯而易見的原因,每個線程都使用while循環,這會消耗相當大量的處理器時間,這是不夠的。從C中的ConcurrentQueue中離隊對象#

有人會知道在需要時將郵件出隊的方法,但不會消耗太多的處理時間。

{ 
    ... 

    for (int i = 0; i < 3; i++) 
    { 
     Thread t = new Thread(new ThreadStart(startParsingMessages)); 
     t.Start(); 
    } 

    ... 
} 

private void startParsingMessages() 
{ 
    QueueContainer dequeued = null; 
    Console.WriteLine("Trying"); 
    while (true) 
    { 
     if (queue.TryDequeue(out dequeued)) 
     { 
      Console.WriteLine("processing queue"); 
      ProcessMessage(dequeued.socket, dequeued.message); 
     } 
    } 
} 

回答

18

而不是直接使用ConcurrentQueue<T>的,你嘗試它包裹在一個BlockingCollection<T>?那麼你可以使用TryTake(out T, TimeSpan)等。我相信這是預期的用途:併發集合本身將通常在那裏,所以你可以選擇阻塞集合的工作方式。

這並不一定是唯一使用爲當然這些集合,但特別是ConcurrentQueue<T>,生產者/消費者隊列的情況是最常見的一種 - 在這一點BlockingCollection<T>是可以很容易的方式做正確的事情。

+1

+1你幾乎意味着併發集合只是有''BlockingCollection',我不知道這是真的。但是,你在這裏使用'BlockingCollection'來減少所有與傳統的生產者/消費者模式相關的儀式。 – Marc 2010-08-17 13:46:07

+0

@Marc:我不會說這是真的,但我認爲那會成爲主要的用途。我會更新答案。 – 2010-08-17 13:49:40

+0

嗨,謝謝你的建議!我將我的ConcurrentQueue包裝在BlockingCollection中,結果非常棒。我通過隊列同時運行20個線程,通過TryTake(out T,TimeSpan s)方法每個線程的阻塞時間爲0.1秒,並且它正在發揮魅力。請求正在適當的時間內處理(比沒有併發隊列更快)並且CPU負載從未降低過。 再次感謝! – user352891 2010-08-20 12:25:07

4

您可以使用靜態鎖定對象讓線程等待,然後在準備好處理某個事件時對其進行脈衝處理。

static readonly object queueLock = new object(); 

// Threads that enqueue an object 
void QueueMessage() { 
    lock (queueLock) { 
    queue.Enqueue(obj); 
    Monitor.Pulse(queueLock); 
    } 
} 
// Thread dequeuer 
private void startParsingMessages() { 
    QueueContainer dequeued = null; 
    Console.WriteLine("Trying"); 
    while (true) { 
    lock(queueLock) { 
     if (!queue.TryDequeue(out dequeued)) { 
     Console.WriteLine("No object to dequeue, waiting..."); 
     // Threads will wait here and only one will be released when .Pulse()d 
     Monitor.Wait(queueLock); 
     dequeued = queue.Dequeue(); 
     } 
     if (dequeued != null) { 
     Console.WriteLine("processing queue"); 
     ProcessMessage(dequeued.socket, dequeued.message); 
     } 
    } 
    } 
} 

請記住,這可以得到你有更多的分支相當複雜,但它的要點是,你鎖在一個共同的目標,並呼籲Monitor.Wait等待的對象上是Pulse d。發生這種情況時,只有一個正在等待的線程將被釋放。如果你排隊了很多對象並且希望它們全部去,你可以調用Monitor.PulseAll這將釋放等待對象的所有線程。

+1

你好,感謝您的建議!我實施了你的建議,結果非常有希望,並提出了很少的要求。然而,一旦有大量的服務需求,響應時間就會大大增加。 再次感謝您的建議,這對我將來的項目來說肯定是一種技巧。 – user352891 2010-08-20 12:28:58