我目前有一个后台主题。在这个线程中是一个无限循环。
此循环偶尔会更新数据库中的某些值,然后在MessageQueue上侦听1秒(使用queue.Receive(TimeSpan.FromSeconds(1))
)。
只要没有消息进入,此调用就会在内部抛出MessageQueueException(Timeout),然后循环继续。如果有消息,则呼叫通常会返回并处理消息,然后循环继续。
这会导致第一次机会异常的批次(每秒,除了有一条要处理的消息),这会使调试输出发生错误,并且当我忘记排除MessageQueueExceptions时也会在调试器中中断。
那么MessageQueue的异步处理是如何正确完成的,同时仍然确保只要我的应用程序运行,就会监视队列,并且数据库也会偶尔更新一次。当然这里的线程不应该耗尽100%的CPU。
我只需要大图或暗示一些正确完成的异步处理。
答案 0 :(得分:4)
我建议为MessageQueue的ReceiveCompleted事件注册一个委托,而不是在一个线程中循环,如下所述:
using System;
using System.Messaging;
namespace MyProject
{
///
/// Provides a container class for the example.
///
public class 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;
}
}
}
//**************************************************
// 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;
}
}
答案 1 :(得分:3)
与Jamie Dixon的评论相反,情景非同寻常。请注意方法及其参数的命名:BeginReceive(TimeSpan timeout)
如果该方法名为BeginTryReceive,那么如果没有收到消息则完全正常。将其命名为BeginReceive(或同步版本的Receive)意味着消息应该进入队列。 TimeSpan参数名为timeout也很重要,因为超时是例外。超时意味着预期响应,但没有给出响应,并且调用者选择停止等待并假定发生了错误。当你以1秒的超时时间调用BeginReceive / Receive时,你会说如果到那时没有消息进入队列,那么一定有问题,我们需要处理它。
我实现这个的方式,如果我理解你想要做的正确,是这样的:
编辑:我有另一个建议。由于我不知道您的申请的细节,我不知道它是否可行或适当。在我看来,你基本上建立了客户端和服务器之间的连接,消息队列作为通信通道。为什么这是一个“连接”?因为如果没有人正在侦听,则不会写入队列。我认为,这几乎就是一种联系。使用套接字或命名管道传输消息不是更合适吗?这样,客户端只需在完成读取后关闭Stream对象,就会立即通知服务器。正如我所说的,我不知道它是否适用于你正在做的事情,但感觉它是一个更合适的沟通渠道。
答案 2 :(得分:3)
您是否考虑过从MessageEnumerator返回的MessageQueue.GetMessageEnumerator2?
MoveNext()
将返回false并且您不需要捕获第一次机会异常