2010-08-17 40 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