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



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

实际上,我正在做的是每个 QueueConnector 对象在构造上创建一个新线程,该线程执行一个无限循环,并阻止对队列的调用。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<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;
}

在这种情况下,我会通过使用任务而不是单独线程中的无限循环(带有阻塞调用 => 阻塞线程)来获得任何好处吗?如果是,如何正确执行此操作?

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

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

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

最新更新