65.9K
CodeProject 正在变化。 阅读更多。
Home

消息队列计数比较

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (7投票s)

2012年3月14日

CPOL

2分钟阅读

viewsIcon

40837

downloadIcon

474

比较在MSMQ上计数消息的不同方法

介绍 

最近我需要创建一个可视化监控多个消息队列中消息数量的手段。 这应该相对简单,创建一个UI来显示myMessageQueue.Count()的结果,但是消息队列类中并不存在count方法。 

游标方法

当我搜索解决方案时,大多数评论都在使用游标。 这是我最初使用的方法,但是当我有大约> 35,000条消息时,我发现计数非常不稳定。 队列中的消息越多,此方法花费的计数时间就越长。  

有关使用游标与MSMQ的完整描述,请参阅Microsoft的http://support.microsoft.com/kb/178516

private MessageQueue _messageQueue;
private int CountCursor()
{
    _messageQueue = new MessageQueue(".\\private$\\pingpong", QueueAccessMode.Peek);
    int count = 0;
    Cursor cursor = _messageQueue.CreateCursor();
    Message m = CursorPeekWithoutTimeout(cursor, PeekAction.Current);
    if (m != null)
    {
        count = 1;
        while ((m = CursorPeekWithoutTimeout(cursor, PeekAction.Next)) != null)
        {
            count++;
        }
        if (m != null) m.Dispose();
    }
    cursor.Dispose();
    return count;
}
protected Message CursorPeekWithoutTimeout(Cursor cursor, PeekAction action)
{
    Message ret = null;
    try
    {
        ret = _messageQueue.Peek(new TimeSpan(1), cursor, action);
    }
    catch (MessageQueueException mqe)
    {
        if (mqe.MessageQueueErrorCode != MessageQueueErrorCode.IOTimeout)
        {
            throw;
        }
    }
    return ret;
}

GetAllMessages方法

GetAllMessages返回队列中消息的静态副本,这对于小型的单次计数来说是可以的。在实际应用中,队列中可能存在数百万条大型消息,因此为了减少带回的信息量,我们需要设置消息过滤器。队列中的消息越多,此方法花费的计数时间就越长。 

var _messageQueue = new MessageQueue(".\\private$\pingpong", QueueAccessMode.Peek);
var countFilter = new MessagePropertyFilter
                        {
                            AdministrationQueue = false,
                            ArrivedTime = false,
                            CorrelationId = false,
                            Priority = false,
                            ResponseQueue = false,
                            SentTime = false,
                            Body = false,
                            Label = false,
                            Id = false
                        };
_messageQueue.MessageReadPropertyFilter = countFilter;
return _messageQueue.GetAllMessages().Length;

GetEnumerator2方法

GetEnumerator2返回队列中消息的动态列表。 队列中的消息越多,此方法花费的计数时间就越长。

var _messageQueue = new MessageQueue(".\\private$\pingpong", QueueAccessMode.Peek);
var x = _messageQueue.GetMessageEnumerator2();
int iCount = 0;
while (x.MoveNext())
{
   iCount++;
}
return iCount;

PowerShell (WMI) 方法

这是迄今为止最快的方法,无论有多少消息需要计数,大约需要20毫秒。这是计数您有权访问的其他机器上的消息队列的唯一方法。 

private int GetPowerShellCount()
{
    return GetPowerShellCount(".\\private$\pingpong", Environment.MachineName, "", "");
}
private  int GetPowerShellCount(string queuePath, string machine,string username, string password)
{
    var path = string.Format(@"\\{0}\root\CIMv2", machine);
    ManagementScope scope;
    if (string.IsNullOrEmpty(username))
    {
            scope = new ManagementScope(path);
    }
    else
    {
        var options = new ConnectionOptions {Username = username, Password = password};
        scope = new ManagementScope(path, options);
    }
    scope.Connect();
    if (queuePath.StartsWith(".\\")) queuePath=queuePath.Replace(".\\",string.Format("{0}\\",machine));
    
    string queryString = String.Format("SELECT * FROM Win32_PerfFormattedData_msmq_MSMQQueue");
    var query = new ObjectQuery(queryString);
    var searcher = new ManagementObjectSearcher(scope, query);
    IEnumerable<int> messageCountEnumerable =
        from ManagementObject queue in searcher.Get()
        select (int)(UInt64)queue.GetPropertyValue("MessagesInQueue");
    //IEnumerable<string> messageCountEnumerable =
    //  from ManagementObject queue in searcher.Get()
    //  select (string)queue.GetPropertyValue("Name");
    var x = messageCountEnumerable.First();
    return x;
}

测试

我决定创建一个测试,该测试将计算消息数量并计算消息计数的时间。要运行源代码中包含的测试,您需要在您的机器上创建一个私有MSMQ,队列的名称无关紧要,因为应用程序将使用它找到的第一个私有队列。测试应用程序需要以管理员身份运行,因为您将在测试开始之前清除消息队列。

参考文献 

© . All rights reserved.