用任务替换无限线程循环(消息泵)

时间:2012-07-05 18:06:11

标签: c# asynchronous task-parallel-library producer-consumer

在我的应用程序中,我必须侦听多个不同的队列并反序列化/分派在队列上收到的传入消息。

实际上,我要做的是每个QueueConnector对象在构造时创建一个新线程,它执行一个无限循环,对queue.Receive()进行阻塞调用,以接收代码公开的队列中的下一条消息下面:

// Instantiate message pump thread
msmqPumpThread = new Thread(() => while (true)
{
   // Blocking call (infinite timeout)
   // Wait for a new message to come in queue and get it
   var message = queue.Receive();

   // Deserialize/Dispatch message
   DeserializeAndDispatchMessage(message);
}).Start();

我想知道是否可以使用Task替换此“消息泵”,而不是在新线程上进行无限循环。

我已经为消息接收部分创建了一个任务(见下文),但我真的没有看到如何将它用于消息泵(我可以一次又一次地重新调用相同的任务,继续,替换单独线程中的无限循环,如上面的代码?)

Task<Message> GetMessageFromQueueAsync()
{
    var tcs = new TaskCompletionSource<Message>();

    ReceiveCompletedEventHandler receiveCompletedHandler = null;

    receiveCompletedHandler = (s, e) =>
    {
       queue.ReceiveCompleted -= receiveCompletedHandler;
       tcs.SetResult(e.Message);
    };

    queue.BeginReceive();

    return tcs.Task;
}

在此上下文中,通过在单独的线程中使用Tasks而不是无限循环(使用阻塞调用=&gt;阻塞线程),我会获得任何收益吗?如果是的话,如何正确地做到这一点?

请注意,此应用程序没有很多QueueConnector对象,并且没有(可能有10个连接器MAX),这意味着第一个解决方案中最多有10个Threads,因此内存占用/性能启动线程不是问题这里。我正在考虑调度性能/ CPU使用率。会有什么不同吗?

1 个答案:

答案 0 :(得分:0)

当线程数低时,您通常会有更多的开销和更少的异步代码吞吐量。当线程数非常高导致a)由于堆栈和b)上下文切换而浪费大量内存时,非阻塞代码最有用。它有明显的开销,因为更多的分配,更多的间接和更多的用户内核转换。

对于低线程数(<100),您可能不必担心。尝试专注于编写可维护,防错和简单的代码。使用线程。