性能计数器NextValue()非常慢(1,000+计数器)

trn*_*son 8 .net c# perfmon performancecounter

在我们的应用程序中,我们使用Windows性能计数器来存储我们的一些应用程序指标,这些指标稍后会在某些Web服务中检索.

我遇到了从计数器读取值所花费的时间问题.我已经浏览了我的应用程序的其余部分,一切都很好,性能明智,但从循环中的计数器(从列表或数组)读取需要花费大量的时间.

示例代码:

// This triggers a read of the counter's initial value (1000ms delay following for calculated counters)
counters.ToList().ForEach(counter => counter.NextValue());
Run Code Online (Sandbox Code Playgroud)

在我对上面的循环的测试中,1,359个计数器的列表需要20秒,并且使用秒表,似乎读取计数器值的平均时间是0-10ms,或大约80-90ms.其中很多都需要0ms,最高约为170ms,平均非零值约为80-90ms.

也许我太乐观了,但我认为读取1,000个数值应该只需要几毫秒.这里有更多的处理工作比我知道的还要多吗?

我实际上在我的逻辑中有另一个循环,它获得计算计数器的第二个值.这只会使情况变得更糟.:)

谢谢!


更新1

我把计数器检索包裹在一个秒表中,我对结果感到惊讶.阅读即使是简单的属性.RawValue仍然需要花费过多的时间.据我所知,计数器基本上都是一样的,检索应该非常快; 奇怪的是,我也看到了网络类别的计数器需要更长时间的模式.

根据http://joe.blog.freemansoft.com/2014/03/windows-performance-counters.html,性能计数器服务的性能甚至不应该是一个考虑因素.

我已将一些秒表结果发布到以下的pastebin:http://pastebin.com/raw.php?i = aDJk2Tru

我的代码如下:

Stopwatch t;
foreach (var c in counters)
{
    t = Stopwatch.StartNew();
    var r = c.RawValue;
    Debug.WriteLine(t.ElapsedMilliseconds.ToString("000") + " - " + c.CategoryName + ":" + c.CounterName + "(" + c.CounterType + ") = " + r);
}
Run Code Online (Sandbox Code Playgroud)

正如您在粘贴中看到的那样,很多读取都是0,但在50-100ms范围内有很多.我真的不明白这是怎么回事.当然,一个计数器值应该和其他值一样快,对吧?

trn*_*son 8

这是我能够找到的关于计数器的内容.请原谅语法; 这是从我发出的有关此问题的电子邮件中提取的.

  • 在我的机器上至少有一个4-5秒的处理时间(在服务器上可能更好或更差,不确定),从计数器类别中读取实例名称.这与一个类别中的计数器数量可以忽略不计.如果您不使用实例计数器,则可以避免这种情况.
  • 我们将所有计数器存储在一个类别中,因此根据我们的情况,不可避免的是,类别最终会有数千个计数器.在我的测试中,一个类别中的计数器越多,性能越差.这似乎有意义,但单个计数器的性能受当前内存中计数器数量的影响,这是奇怪的相关性,可能:
    • 总计8个计数器,每个计数器的读取时间约为1-2ms
    • 共有256个计数器,每个计数器的读取时间约为15-18ms
    • 总计512个计数器,每个计数器的读取时间约为30ms
    • 共计3,584个计数器(读取所有计数器),每个计数器的读取时间约为200ms
    • 系统中有3,584个计数器(在内存中过滤掉,只能读取512个计数器),每个计数器的读取时间为50-90ms.不知道为什么这些比前一批512计数器慢.
    • 我使用System.Diagnostics.Stopwatch它们来计算这些测试中的每一个.
  • 值得注意的是,计数器必须被读取两次这一事实,因为许多计数器是在一段时间内计算出来的,并且在开始和结束读取时间之间呈现平均值,因此这些不良数字在实际场景中变得更糟.

鉴于上面的数字,在我的机器上,慢速端各有大约50ms的512个计数器,加上实例查询,第二个计数器读取,我们每个请求大约需要60秒.这是因为我们一次只使用512个计数器.我已经多次针对我的机器上的服务运行完整查询,并且请求在60-65秒内始终完成.

基于所评估的其他计数器的数量,我当然不会假设单个计数器的这种性能下降.在我的阅读中,Windows性能监视器系统应该是快速的,并且当然是小型集合.我们的用例可能不太合适,我们可能会滥用系统.

更新

鉴于我们可以控制我们如何创建计数器,我们决定改变我们的方法.我们改为创建许多类别,而不是几个具有许多计数器的类别,每个类别都有较少的计数器(每个类别4-8个计数器).这种方法使我们能够有效地避免性能问题,并且计数器读取时间在0-1ms范围内.根据我们迄今为止的经验,即使是100个新类别,每个类别都有几个计数器,也不会影响系统的性能.

在处理大量额外计数器时,需要注意的是,您需要解决默认情况下为性能计数器设置的内存限制.这可以通过machine.config或注册表项来完成.更多信息可以在这里找到:http://msdn.microsoft.com/en-us/library/ms229387(v = vs1010).aspx