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

C# 将无限线程循环(消息泵)替换为任务,c#,asynchronous,task-parallel-library,producer-consumer,C#,Asynchronous,Task Parallel Library,Producer Consumer,在我的应用程序中,我必须监听多个不同的队列,并对队列上接收到的传入消息进行反序列化/分派 实际上,我要做的是,每个QueueConnector对象在构造时创建一个新线程,该线程通过对queue.Receive()的阻塞调用执行一个无限循环,以接收队列中的下一条消息,如下代码所示: // Instantiate message pump thread msmqPumpThread = new Thread(() => while (true) { // Blocking call (i

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

实际上,我要做的是,每个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();
我想知道这个“消息泵”是否可以用任务代替,而不是在新线程上通过无限循环

我已经为消息接收部分做了一个任务(见下文),但我真的不知道如何将其用于消息泵(我能回忆起完成时的同一个任务吗,重复,替换上面代码中单独线程中的无限循环?)

任务GetMessageFromQueueAsync() { var tcs=new TaskCompletionSource(); ReceiveCompletedEventHandler receiveCompletedHandler=null; receiveCompletedHandler=(s,e)=> { queue.ReceiveCompleted-=receiveCompletedHandler; tcs.SetResult(e.Message); }; queue.BeginReceive(); 返回tcs.Task; } 在这个上下文中,在一个单独的线程中(使用阻塞调用=>blocking thread)使用任务而不是无限循环,我会得到什么?如果是,如何正确地进行


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

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


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

这是一个tipycal生产者-消费者场景,可以使用,特别是感谢Paolo!然而据我所知,生产者/消费者队列更适合于计算范围内的任务(执行密集计算),而TaskCompletionSource/异步函数更适合于I/O范围内的任务(等待某些事情发生)。由于我的问题是处理I/O绑定的任务(等待消息进入队列),因此我认为TaskCompletionSource更合适。不过我可能错了。谢谢你的回答。尽管如此,如果每个QueueConnector对象使用一个带有无限循环的专用线程来接收消息(我当前的方法),那么线程每次到达阻塞队列.receive()调用时都将进行上下文切换。消息到达后,线程中的另一个上下文切换返回。对吗?我已经读到,任务可以使用线程池来减少启动延迟(在我的上下文中不需要),但对于TaskCompletionSource,它们也可以使用回调方法,避免使用线程等待I/O绑定操作(意味着没有上下文切换?),异步非阻塞代码导致更少的上下文切换。如果你想找出哪个版本更快,你需要尝试一下,因为两者都有理由。我的观点是,这可能不值得这么麻烦。您每秒有多少队列操作?少于10公里?那么,从性能的角度来看,这并不重要。
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;
}