_cuclife.com
当前位置:cuclife.com > IT > ASP.NET >

线程性能:Visual Studio 2010 中的资源争用并发分析

随着多核处理器变得越来越常见,软件开发人员就需要构建多线程应用程序,从而利用更多的处理能力来实现更高的性能。借助并行线程的强大功能,您可以将整个工作划分为多项单独的任务,并以并行模式执行这些任务。

  但是,线程经常需要相互通信才能完成任务;而且根据算法或数据访问的要求,有时还需要同步线程的行为。例如,应该以互斥的方式授予线程对同一数据的同时写访问权限,以避免数据损坏。

  同步操作通常是通过使用共享的同步对象来完成的。对于获得该对象的线程,将授予其对敏感代码或数据的共享或独占访问权限。当不再需要访问权限时,该线程将放弃所有权,而其他线程就可以尝试获取访问权限。根据所使用的同步类型,同时请求所有权可能会使多个线程能够同时访问共享资源,也可能会阻止某些线程,直到共享对象从上一次获取中释放为止。具体的示例包括:C/C++ 中使用 EnterCriticalSection 和 LeaveCriticalSection 访问例程的关键部分,C/C++ 中的 WaitForSingleObject 函数,以及 C# 中的锁定语句和 Monitor 类。

  选择同步机制时必须谨慎,因为不恰当的线程同步不但不能提高性能,反而会降低性能,这与多线程的目标背道而驰。因此,能否检测由于锁争用没有进展而导致线程被阻止的情况,就显得愈加重要。

  Visual Studio 2010 中的性能工具包含一种新的分析方法“资源争用分析”,此方法有助于检测线程间的并发争用。在 John Robbins 的 Wintellect 博客文章中,您可以看到对此功能的精彩简介,其网址为:wintellect.com/CS/blogs/jrobbins/archive/2009/10/19/vs-2010-beta-2-concurrency-resource-profiling-in-depth-first-look.aspx。

  在本文中,我将演练一个争用分析调查,并讲解可以使用 Visual Studio 2010 IDE 和命令行工具收集的数据。此外,还将向您展示如何在 Visual Studio 2010 中分析数据,您会看到,在执行争用调查时,如何从一个分析视图切换到另一个分析视图。然后,我会修改代码,并将修改过的应用程序的分析结果与原来的分析结果进行比较,验证所做的修改确实减少了争用的数量。

  从问题开始

  作为示例,我将使用 Hazim Shafi 在其博客文章“性能模式 1:识别锁争用”(blogs.msdn.com/hshafi/archive/2009/06/19/performance-pattern-1-identifying-lock-contention.aspx) 中使用的同一个矩阵乘法应用程序。尽管代码示例是用 C++ 编写的,但是我讨论的概念同样适用于托管代码。

  示例矩阵乘法应用程序使用多个线程对两个矩阵执行乘法操作。每个线程都将承担一部分工作,并运行以下代码段:

for (i = myid*PerProcessorChunk; 
   i < (myid+1)*PerProcessorChunk; 
   i++) { 
 EnterCriticalSection(&mmlock); 
 for (j=0; j<SIZE; j++) { 
  for (k=0; k<SIZE; k++) { 
   C[i][j] += A[i][k]*B[k][j]; 
  } 
 } 
 LeaveCriticalSection(&mmlock); 
}

  每个线程都有自己的 ID (myid),并且负责使用矩阵 A 和 B 作为输入,来计算结果矩阵 C 中的行数(一行或多行)。深入的代码检测表明,没有发生真正引起歧义的写共享,每个线程都写入 C 的不同行。然而,开发人员还是决定使用关键部分来保证对矩阵的赋值。我要感谢开发人员的这个决定,因为这给了我一个好机会,来展示新的 Visual Studio 2010 性能工具能够轻松发现冗余的同步。

  分析数据集合

  假设您有一个 Visual Studio 项目,其中的代码如上文所示(但这不是必需的,因为您可以将分析器连接到任何一个处在运行中的应用程序),您单击“分析”菜单上的“启动分析向导”开始进行争用分析。

  在该向导的第一个页面上(如图 1 所示),选择“并发”,并确保选中“收集资源争用数据”选项。请注意,资源争用并发分析适用于任何版本的 Windows 操作系统。但“显示多线程应用程序的行为”选项仅适用于 Windows Vista 或 Windows 7。


图 11 性能资源管理器的分析控件

  Visual Studio UI 能够自动执行收集分析数据所需的多个步骤。但也可以使用命令行工具来收集分析数据,这种方法对于自动化操作和脚本很有用。

  若要在争用分析模式下启动应用程序,请打开 Visual Studio 命令提示符(它将所有的分析器二进制文件都放到您的路径中,无论是 x86 还是 x64 工具),然后执行以下输入操作:

  VSPerfCmd.exe /start:CONCURRENCY,RESOURCEONLY /output:<您的输出文件>

  VSPerfCmd.exe /launch:<您的应用程序> /args:"<您的应用程序参数>"

  运行您的方案

  VSPerfCmd.exe /detach

  如果您的应用程序已终止,则此步骤不是必需的,但此步骤没有任何危害,因此您可以将其添加到脚本中。

  VSPerfCmd.exe /shutdown

  现在,您可以在 Visual Studio 中打开 YourOutputFile.VSP 进行分析了。

  如果您的应用程序已经在运行中,则可以按照以下步骤将分析器连接到该应用程序:

  VSPerfCmd.exe /start:CONCURRENCY,RESOURCEONLY /output:<您的输出文件>

  VSPerfCmd.exe /attach:<PID 或进程名称>

  运行您的方案

  VSPerfCmd.exe /detach

  VSPerfCmd.exe /shutdown

  有关可用命令行选项的更详细说明,请访问以下网址:msdn.microsoft.com/library/bb385768(VS.100)。

  您可以利用多种 Visual Studio 视图来深入检查所收集的数据。有些视图会显示应用程序生命周期的整体概况,而另一些视图则专门显示特定的争用,您可以使用您认为最有用的视图。

  当您对分析结果进行分析时,可以借助超链接、双击或上下文菜单在不同视图之间切换,也可以通过下拉菜单直接切换到任何可用的视图。图 12 简要介绍了每种视图。

  图 12 分析视图

视图 说明

摘要 “摘要”信息为您的调查提供了一个良好的起点。这是您看到的第一个视图。当分析会话结束且结果文件准备就绪之后,它会自动打开。

调用树 一个聚集了所有争用堆的调用树。您可以在此看到是哪些堆导致了争用。

模块 一个模块列表,这些模块所包含的每个函数都导致了一个争用。每个模块都包含相关函数的列表以及检测到的争用次数。

调用方/被调用方 包含三个面板的视图,这些面板分别显示函数 F、调用 F 的所有函数,以及 F 调用的所有函数(当然,仅限导致争用的调用)。

函数 在任何争用堆上检测到的所有函数及其相关数据的列表。

行 源代码中的函数行。

资源详细信息 关于特定资源(例如锁)的详细信息,将显示应用程序生命周期内被该资源阻止的所有线程。

线程详细信息 关于特定线程的详细信息,将显示阻止该线程的所有资源(例如锁)。

争用 与调用树视图相似,但在此处,调用树是按争用资源划分的。也就是说,此视图将显示一组调用树,每个树分别包含被某种特定资源阻止的堆。

标记 自动和手动记录的标记列表,其中每个标记都关联了其时间戳以及 Windows 计数器的值。

进程 经检查的进程列表,其中每个进程都具有其线程列表,而每个线程都显示其经历的争用次数以及被阻止的总时间长度。

函数详细信息 关于特定函数的详细信息,包括它调用的函数以及收集的数据。

IP 发生争用的指令指针的列表(即,诸如 EnterCriticalSection、WaitForSingleObject 等之类函数的列表,因为这是争用实际发生的位置)。

借助 Visual Studio 中新的资源争用分析功能,您可以发现由于在代码中使用线程同步而导致的性能问题,并能够在运行时通过更改、减少或消除不必要的同步来提高应用程序的性能。

文章来源:网络整理  本站编辑:兰特
上一篇:透视 WPF 应用程序的利器
下一篇:输入验证:通过 WPF 强制执行复杂的业务数据规则
评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)