我目前有一个后台主题。在这个线程中是一个无限循环。
这个循环偶尔会更新数据库中的某些值,然后在MessageQueue上监听1秒(使用queue.Receive(TimeSpan.FromSeconds(1))
)。
只要没有消息进入,此调用就会在内部抛出MessageQueueException(Timeout),然后循环继续。如果有消息,则呼叫通常会返回并处理消息,之后循环继续。
这导致了许多第一次机会异常(每秒,除了有一条要处理的消息)并且这会阻止调试输出,并且当我忘记排除MessageQueueExceptions时也会在调试器中中断。
那么如何正确地完成MessageQueue的异步处理,同时仍然确保只要我的应用程序运行,就会监视队列并且偶尔也会更新数据库。当然这里的线程不应该耗尽100%的CPU。
我只需要大图或暗示一些正确完成的异步处理。
你有没有考虑过从MessageEnumerator归来的MessageQueue.GetMessageEnumerator2?
MoveNext()
将返回false并且您不需要捕获第一次机会异常我建议不要在线程中循环,而是为MessageQueue的ReceiveCompleted事件注册一个委托,如下所述:
使用系统;使用System.Messaging;
namespace MyProject {/// ///为示例提供容器类。 ///公共类MyNewQueue {
//**************************************************
// Provides an entry point into the application.
//
// This example performs asynchronous receive operation
// processing.
//**************************************************
public static void Main()
{
// Create an instance of MessageQueue. Set its formatter.
MessageQueue myQueue = new MessageQueue(".\\myQueue");
myQueue.Formatter = new XmlMessageFormatter(new Type[]
{typeof(String)});
// Add an event handler for the ReceiveCompleted event.
myQueue.ReceiveCompleted += new
ReceiveCompletedEventHandler(MyReceiveCompleted);
// Begin the asynchronous receive operation.
myQueue.BeginReceive();
// Do other work on the current thread.
return;
}
//**************************************************
// Provides an event handler for the ReceiveCompleted
// event.
//**************************************************
private static void MyReceiveCompleted(Object source,
ReceiveCompletedEventArgs asyncResult)
{
// Connect to the queue.
MessageQueue mq = (MessageQueue)source;
// End the asynchronous Receive operation.
Message m = mq.EndReceive(asyncResult.AsyncResult);
// Display message information on the screen.
Console.WriteLine("Message: " + (string)m.Body);
// Restart the asynchronous Receive operation.
mq.BeginReceive();
return;
}
}
}
与Jamie Dixon的评论相反,情景非同寻常。请注意方法及其参数的命名:BeginReceive(TimeSpan超时)
如果该方法被命名为BeginTryReceive,如果没有收到消息,那将是完全正常的。将其命名为BeginReceive(或同步版本的Receive)意味着消息应该进入队列。 TimeSpan参数名为timeout也很重要,因为超时是例外。超时意味着预期响应,但没有给出响应,并且调用者选择停止等待并假定发生了错误。当你用1秒的超时调用BeginReceive / Receive时,你会说如果到那时没有消息进入队列,那么肯定会出错,我们需要处理它。
我实现这个的方式,如果我理解你想要做的正确,是这样的:
编辑:我有另一个建议。由于我不知道您的申请的细节,我不知道它是否可行或适当。在我看来,你基本上建立了客户端和服务器之间的连接,消息队列作为通信通道。为什么这是一个“连接”?因为如果没有人正在侦听,则不会写入队列。我认为,这几乎就是一种联系。使用套接字或命名管道传输消息不是更合适吗?这样,客户端只需在完成读取后关闭Stream对象,就会立即通知服务器。正如我所说的,我不知道它是否适用于你正在做的事情,但感觉它是一个更合适的沟通渠道。