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

.NET 最佳实践编号:3:使用性能计数器收集性能数据

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.83/5 (52投票s)

2009 年 9 月 1 日

CPOL

14分钟阅读

viewsIcon

255143

downloadIcon

896

.NET 最佳实践编号:3:使用性能计数器收集性能数据

已更新 .NET 最佳实践编号 1、2、4、5 和视频链接

.NET 最佳实践编号:3:使用性能计数器收集性能数据

我的其他最佳实践文章

本文是否值得继续阅读?

引言:我的应用程序性能像火箭一样出色 J

感谢 Javier 和 Michael

归根结底,就是计数、计算和显示

性能计数器不是万能的

应用程序中测量的类型

将要测试性能计数器的示例

用 4 个步骤添加我们的第一个瞬时性能计数器

创建更有意义的计数器

平均性能计数器

速率性能计数器

剩余性能计数器

通过 C# 代码添加计数器

使用性能计数器助手来减轻一些痛苦

请勿在生产环境中使用

结论

源代码

其他实践

我的 FAQ 文章

使用 finalize/dispose 模式提高垃圾回收器性能

本文是否值得继续阅读?

本文将讨论如何使用性能计数器从应用程序收集数据。因此,我们将首先理解基本原理,然后看一个简单的示例,从中收集一些性能数据。

引言:我的应用程序性能像火箭一样出色 J

让我们从一段客户和开发人员之间的简短对话开始本文。

场景 1

客户:您的应用程序性能如何?
主观开发者:嗯,它速度很快,它是最好的……呼啊啊啊,它像火箭一样。

场景 2
客户:您的应用程序性能如何?
量化开发者:在 2GB RAM、xyz 处理器和 20000 条客户记录的情况下,客户屏幕加载需要 20 秒。

我相信第二位开发人员比第一位更有希望。在本文中,我们将探讨如何使用性能计数器来衡量应用程序的性能。所以,让我们开始计数 1,2,3,4……。


资料来源:http://scoutbase.org.uk 

感谢 Javier 和 Michael

我确实没有写性能计数器文章的知识。但阅读了以下文章后,我设法写了一些东西。所以,首先我要感谢这些家伙,然后我们就可以继续阅读本文了。

非常感谢 Javier Canillas 创建了性能计数器助手,它极大地简化了许多代码 http://perfmoncounterhelper.codeplex.com/ 

感谢 Michael Groeger 的精彩文章,我从您的文章中获取了计数器创建代码 https://codeproject.org.cn/KB/dotnet/perfcounter.aspx 

我还从 http://msdn.microsoft.com/en-us/library/system.diagnostics.performancecounter.aspx 中获取了许多要点 

归根结底,就是计数、计算和显示

任何性能评估都围绕着计数、计算和显示。例如,如果您想计算每秒处理了多少内存页面,我们首先需要计算页面数,还需要计算经过了多少秒。一旦我们完成了计数,我们就需要计算,即用页面数除以经过的时间(秒)。最后,我们需要显示性能数据。

现在我们知道这是一个 3 步过程,即计数、计算和显示。计数部分由应用程序完成。所以,应用程序需要在计数阶段提供数据。请注意,性能计数器不会自动检测数据,需要应用程序提供一些帮助。计算和显示由性能计数器和监视器完成。

性能计数器不是万能的

如果应用程序不提供计数器数据,性能计数器就无法自行测量。性能计数器无法测量不提供性能数据的应用程序。换句话说,应用程序需要通过创建性能计数器对象来提供计数器数据。

应用程序中测量的类型

几乎所有的应用程序性能测量都属于以下六个类别之一。

瞬时值: 很多时候我们只想衡量最近的值。例如,我们只想衡量处理了多少客户记录?使用了多少 RAM 内存等。这些类型的度量称为瞬时值或绝对值。性能计数器通过使用瞬时计数器支持这些度量类型。

平均值: 有时瞬时/最近值并不能真正显示真实情况。例如,仅仅说应用程序消耗了 1GB 空间是不够的。但是,如果我们能获得一些平均数据消耗,例如每 1000 条记录消耗 10MB 数据,您可能会更深入地了解应用程序内部发生的事情。性能计数器通过使用平均性能计数器(如 AverageBase、AverageTimer32、AverageCount64 等)支持这些类型的度量。

速率值: 有时您想知道事件相对于时间的速率。例如,您想知道每秒处理了多少条记录。速率计数器可以帮助我们计算这些类型的性能指标。

百分比值: 很多时候我们想将值作为百分比来方便比较。例如,您想比较两台计算机之间的性能数据。直接比较值是不公平的。因此,如果我们能获得两台计算机的百分比值,比较就会更有意义。如果您想比较不同性能计数器之间的值,百分比比使用绝对值是更好的选择。

例如,如果您想比较 RAM 的使用量与硬盘空间的占用量。比较 1GB 的 RAM 使用量和 50GB 的硬盘使用量,就像比较苹果和橘子。如果能将这些值表示为百分比,则比较将是公平且有据可查的。百分比性能计数器可以帮助我们将绝对值表示为百分比。

差值: 很多时候我们想获得差值性能数据,例如,从应用程序启动到现在经过了多少时间,应用程序从启动到现在消耗了多少硬盘空间等。为了收集这些类型的性能数据,我们需要记录原始值和最近的值。要获得最终的性能数据,我们需要从最近的值中减去原始值。性能计数器提供差值计数器来计算此类性能数据。

因此,总结一下,有 5 种性能计数器可以满足以上所有计数需求。下图以图示形式展示了这一点。

将要测试性能计数器的示例

在本文中,我们将考虑一个简单的计数器示例,如下所示。在这个示例中,我们将有一个定时器,每 100 毫秒生成一个随机数。然后检查这些随机数是否小于 2。如果小于 2,则调用函数 'MyFunction'。

以下是定时器每 100 毫秒运行并计算随机数的代码。如果随机数小于 2,我们则调用函数 'MyFunction'。

private void timer1_Tick(object sender, EventArgs e)
{
// Generate random number between 1 to 5.
Random objRnd = new Random();
int y = objRnd.Next(1, 5);

// If random number is less than 2 call my Function
if (y > 2)
{
MyFunction();
}
}

以下是当随机数小于 2 时调用的 'MyFunction' 的代码。该方法本身不做任何事情。

private void MyFunction()
{

}

本文中我们所有的性能计数器示例都将使用上述定义的样本。

用 4 个步骤添加我们的第一个瞬时性能计数器

在深入了解如何添加性能计数器之前,让我们先了解一下性能计数器的结构。当我们创建性能计数器时,它需要属于某个组。因此,我们需要创建一个类别,所有性能计数器都将在此类别下。

我们只想计算 'MyFunction' 被调用了多少次。所以,让我们创建一个名为 'NumberOfTimeFunctionCalled' 的瞬时计数器。在继续之前,让我们看看性能计数器提供了多少种不同的瞬时计数器类型。

以下定义来自 http://msdn.microsoft.com/en-us/library/system.diagnostics.performancecountertype.aspx

NumberOfItems32:一个瞬时计数器,显示最近观察到的值。

NumberOfItems64:一个瞬时计数器,显示最近观察到的值。例如,用于维护大量项或操作的简单计数。它与 NumberOfItems32 相同,只是使用了更大的字段来容纳更大的值。

NumberOfItemsHEX32:一个瞬时计数器,以十六进制格式显示最近观察到的值。例如,用于维护项或操作的简单计数。

NumberOfItemsHEX64:一个瞬时计数器,显示最近观察到的值。例如,用于维护大量项或操作的简单计数。它与 NumberOfItemsHEX32 相同,只是使用了更大的字段来容纳更大的值。

步骤 1 创建计数器:对于我们当前的情况,‘NumberOfItems32’ 就足够了。所以,让我们先创建‘NumberOfItems32’瞬时计数器。有两种方法可以创建计数器:一种是通过代码,另一种是使用 VS 2008 的服务器资源管理器。代码方法我们稍后会看到。目前,我们将使用服务器资源管理器来创建我们的计数器。所以,打开您的 visual studio -> 点击视图 -> 服务器资源管理器,您应该会看到性能计数器部分,如下图所示。右键单击性能计数器部分,然后选择创建新类别。

当我们创建一个新类别时,您可以指定类别的名称并将计数器添加到该类别中。对于当前示例,我们将类别名称设置为‘MyApplication’,并添加了一个‘NumberOfItem32’类型的计数器,名称为‘NumberOfTimeFunctionCalled’。

步骤 2 将计数器添加到您的 visual studio 应用程序:添加完服务器资源管理器上的计数器后,您可以像下图所示一样将计数器拖放到 ASPX 页面上。
您需要将‘ReadOnly’值设置为 false,以便您可以从代码中修改计数器值。

步骤 3 添加代码来计数计数器:最后,我们需要递增计数器。我们在表单加载期间首先清除了计数器中的任何旧值。请注意,计数器值是全局存储的,它们不会自行重置,我们需要显式执行此操作。因此,在表单加载时,我们将原始值清零。

private void Form1_Load(object sender, EventArgs e)
{
perfNumberOfTimeFunctionCalled.RawValue = 0;
}

每当调用该函数时,我们都使用‘Increment’方法来递增该值。每次调用 increment 函数会将数字增加 1。

private void MyFunction()
{
perfNumberOfTimeFunctionCalled.Increment();
}

步骤 4 查看计数器数据:既然我们已经在应用程序中指定了每次调用‘MyFunction’函数时都会递增的计数器。现在是时候使用性能监视器来显示性能计数器了。所以,转到开始 -> 运行,然后键入‘perfmon’。您会看到很多默认性能计数器。为了清晰起见,我们将暂时移除所有计数器,然后添加我们的性能计数器,即‘NumberofTimeFunctionCalled’。

您现在可以看到图形显示,如下图所示。确保您的应用程序正在运行,因为应用程序会发出数据,然后由性能监视器进行解释。

上面的视图是同一个图形视图。要在文本格式中查看,请使用性能监视器提供的视图报告选项卡。您可以看到报告显示‘MyFunction’自应用程序启动以来被调用了 9696 次。

创建更有意义的计数器

在上一节中,我们测量了‘MyFunction’被调用了多少次。但这个性能计数并不能真正显示任何衡量标准。如果我们还能看到定时器被调用了多少次的计数,那将是很好的。然后,我们可以比较定时器被调用次数和‘MyFunction’被调用次数。

所以,创建一个瞬时计数器,并在定时器触发时递增此计数器,如下面的代码所示。

private void timer1_Tick(object sender, EventArgs e)
{
perfNumberOfTimeTimerCalled.Increment();
Random objRnd = new Random();
int y = objRnd.Next(1, 5);
if (y > 2)
{
MyFunction();
}
}

您可以在下面的图形中看到两个计数器,蓝线表示‘MyFunction’被调用的次数,黑线表示定时器被调用的次数。

如果我们查看报告视图,我们可以看到定时器触发了多少次,以及‘MyFunction’被调用了多少次。

平均性能计数器

在上一节中,我们计数了两个计数器,一个表示定时器触发了多少次,另一个表示‘MyFunction’被调用了多少次。如果我们能获得某种平均数据,说明‘MyFunctionCalled’相对于定时器调用次数的平均值,那将更有意义。

为了获得这些指标,可以使用平均性能计数器。因此,对于我们的场景,我们需要计算函数被调用的次数以及定时器触发的次数。然后,我们需要将它们相除,以找出平均而言,函数对于定时器触发了多少次。

我们需要添加两个计数器,一个作为分子,另一个作为分母。对于分子计数器,我们需要添加‘AverageCount64’类型的计数器,而对于分母,我们需要添加‘AverageBase’类型的计数器。

您需要在‘AverageCount64’类型计数器之后添加‘AverageBase’计数器,否则您会收到如下所示的错误。

对于每次定时器滴答,我们都会递增定时器调用次数计数器。

private void timer1_Tick(object sender, EventArgs e)
{
perfAvgNumberofTimeTimerCalled.Increment();
Random objRnd = new Random();
int y = objRnd.Next(1, 5);
if (y > 2)
{
MyFunction();
}
}

对于每次函数调用,我们都会递增函数调用次数计数器。

private void MyFunction()
{

perfNumberOfTimeFunctionCalled.Increment();

}

如果您在报告视图模式下运行应用程序,您应该会看到如下所示的内容。您可以看到平均而言,‘MyFunction’被调用了 0.5 次。

如果您进行计算,您将得到与性能监视器计算出的相同数字。

速率性能计数器

根据我们的示例,我们现在想找出‘MyFunction’调用相对于时间的速率。所以,我们想知道每秒有多少次调用。因此,请浏览到服务器资源管理器,然后添加‘rateofCountsPerSecond32’计数器,如下图所示。每次调用‘MyFunction’时,增加此计数器。

如果您运行应用程序,您应该能够看到‘RateofMyFunctionCalledPerSecond’的值。下面是一个简单的报告,显示了运行了 15 秒的计数器数据的速率。在此 15 秒内总共进行了 72 次调用。因此,平均每秒调用‘MyFunction’ 5 次。

剩余性能计数器

我们保留了百分比计数器和差值计数器,因为它们相当简单明了。为了使本文保持重点和具体,我省略了这两种计数器类型。

通过 C# 代码添加计数器

到目前为止,我们已经使用服务器资源管理器添加了性能计数器。您也可以通过代码添加计数器。首先,我们需要导入 `System.Diagnostics` 命名空间。

然后我们需要创建一个‘CounterCreationDataCollection’对象。

CounterCreationDataCollection Mycounters = new CounterCreationDataCollection();

创建我们的实际计数器并指定计数器类型。

CounterCreationData totalOps = new CounterCreationData();
totalOps.CounterName = "Numberofoperations";
totalOps.CounterHelp = "Total number of operations executed";
totalOps.CounterType = PerformanceCounterType.NumberOfItems32;
Mycounters.Add(totalOps);

最后,在类别中创建计数器。下面的代码片段正在‘MyCategory’类别中创建计数器。

PerformanceCounterCategory.Create("MyCategory","Sample category for Codeproject", Mycounters);

使用性能计数器助手来减轻一些痛苦

编写计数器创建代码非常麻烦。您可以使用性能计数器助手来简化和缩短代码。您可以在 http://perfmoncounterhelper.codeplex.com/ 找到性能计数器助手,

请勿在生产环境中使用

哦,是的,只在开发时使用它。如果您在生产环境中使用,请确保有一个启用和禁用的机制,否则它会影响您的应用程序性能。

结论

  • 使用性能计数器来衡量应用程序数据。
  • 性能计数器有各种类别,如瞬时、平均、速率等。
  • 性能计数器不应在生产环境中使用。如果使用,应有禁用机制。
  • 性能计数器本身无法测量,应用程序需要提供数据,以便性能监视器可以计算和显示数据。

源代码

您可以在此处下载上述性能计数器的示例源代码:KB/aspnet/DOTNETBestPractices3/windowsformcounters.zip

其他实践

有关最佳实践第 1 部分,请点击 此处

有关最佳实践第 2 部分,请点击 此处

有关最佳实践第 4 部分,请点击 此处

有关最佳实践第 5 部分,请点击 此处

我的 FAQ 文章

我明白这并非讨论我的 FAQ 的正确文章。只是想表扬自己完成了我的 FAQ 系列一年的写作。下面是所有 FAQ 的汇总链接。

Silverlight FAQ:https://codeproject.org.cn/KB/WPF/WPFSilverLight.aspx 

LINQ FAQ:https://codeproject.org.cn/KB/linq/LINQNewbie.aspx 

WWF FAQ:https://codeproject.org.cn/KB/WF/WWF.aspx

WCF FAQ:WCF.aspx 

Sharepoint FAQ:SharePoint.aspx

Ajax FAQ:AjaxQuickFAQ.aspx 

架构 FAQ:SoftArchInter1.aspx
 
本地化和全球化:LocalizationGlobalizPart1.aspx

项目管理 FAQ:ProjectManagementFAQ.aspx

为了进一步阅读,请观看以下面试准备视频和分步视频系列。

 

© . All rights reserved.