提升 Hilo(使用 C++ 和 XAML 的 Windows 应用商店应用)的性能

Applies to Windows only

来源: 开发使用 C++ 和 XAML 的端对端 Windows 应用商店应用:Hilo

模式 & 最佳实践徽标

上一页 | 下一页

Hilo C++ 团队在构建快速流畅的应用时花了很多时间来了解它有哪些功能、缺少哪些功能。我们确定了应用中需要提升假想性能和实际性能的部分。以下是创建性能良好的响应式应用的一些提示和编码指南。

下载

下载 Hilo 示例
下载书籍 (PDF)

下载代码之后,有关说明,请参阅 Hilo 入门

你将了解

  • 性能和感受到的性能之间的差别。
  • 分析应用时的推荐策略。
  • 帮助创建快速流畅的应用的提示。
  • 如何通过在后台线程上运行计算密集型操作使应用的 UI 保持响应。

适用于

  • Windows 8 的 Windows 运行时
  • Visual C++ 组件扩展 (C++/CX)
  • XAML

通过应用分析提高性能

用户对应用有很多期望。他们希望应用能够立即响应触摸、单击、手势以及按键操作。他们希望动画平滑且流畅,并且用户无需等待应用跟上这些动画。

性能问题会以各种方式出现。这些问题会缩短电池寿命、导致平移和滚动落后于用户的手指,甚至使应用看起来在一段时间之内没有响应。确定代码优化对于减少性能问题最有效的一个方法就是执行应用分析。

使用 Windows 应用商店应用的分析工具,可测量、评估以及针对代码中与性能相关的问题。探查器通过使用采样方法(该方法定期收集 CPU 调用堆栈信息)收集应用的计时信息。分析报告显示有关你的应用性能的信息,并且帮助你浏览代码的执行路径以及函数的执行开销,以便你可以找到最佳优化机会。有关详细信息,请参阅如何在本地计算机上分析 Windows 应用商店应用中的 Visual C++、Visual C# 和 Visual Basic 代码。 若要查看如何分析从探查器返回的数据,请参阅分析 Windows 应用商店应用中的 Visual C++、Visual C# 和 Visual Basic 代码的性能数据

优化性能不仅仅只是实现有效的算法。用户使用应用时,还可以将性能视为用户对应用性能的感知。可以将用户的应用体验分为三类 – 感知、容忍和响应。

  • 感知。用户的性能感知可以定义为当他们回想起在应用中执行任务时有多少赞成的体验。这种感知并不总是与现实相符。可以通过缩短用户为了在应用中完成任务所需执行的活动之间的时间来提高感知的性能。
  • 容忍。用户对延迟的容忍取决于用户预期操作花费的时间长短。例如,如果应用在裁剪过程中变得没有响应,即使是几秒的时间,用户也会认为裁剪图像是无法容忍的事。用户对延迟的容忍程度可以通过以下方法来提高:确定应用中需要大量处理时间的区域,以及通过提供进度的视觉指示来限制或消除在这些方案中用户的不确定性。此外,还可以使用异步 API 来避免阻止 UI 线程以及使应用看起来被冻结。
  • 响应性。应用的响应性与正在执行的活动有关。若要测量和评定某个活动的性能,必须设定一个时间间隔以进行对比。Hilo 团队使用了启发,即,如果某个活动的时间超过 500 毫秒,那么应用可能需要采用直观的形式指示进度,从而向用户提供反馈。

分析提示

当分析应用时,遵循以下提示可确保进行的性能测量可靠并且可重复:

  • Windows 8 在各种设备上运行,并且在某个硬件项目上进行的性能测量并不总是显示其他设备的性能特性。
  • 确保正在捕获性能测量值的计算机已接通电源,而不是使用电池运行。当使用电池运行时很多系统会节省电源,因此运行方式不同。
  • 确保系统上的总内存利用率低于 50%。如果较高,请关闭一些应用,直到达到 50%,目的是确保你正在测量的是对你的应用的影响,而不是其他进程。
  • 当远程分析某个应用时,建议你在远程设备上直接与你的应用交互。尽管你可以通过远程桌面连接与你的应用交互,但这会大大改变应用的性能以及你所收集的性能数据。有关详细信息,请参阅如何在远程计算机上分析 Windows 应用商店应用中的 Visual C++、Visual C# 和 Visual Basic 代码
  • 为了收集最精确的性能结果,需要对应用的发布版本进行分析。请参阅如何设置调试和发布配置
  • 避免在模拟器中分析你的应用,因为模拟器会改变应用的性能。

其他性能工具

除了使用分析工具测量应用性能之外,Hilo 团队还使用了 Windows 可靠性和性能监视器 (perfmon)。可以使用 Perfmon 实时检查运行的程序如何影响计算机的性能,也可以收集日志数据供以后分析使用。Hilo 团队使用这个工具对应用的性能进行常规诊断。有关 perfmon 的详细信息,请参阅 Windows 可靠性和性能监视器

[顶部]

性能提示

Hilo 团队在构建快速流畅的应用时花了很多时间来了解它有哪些功能、缺少哪些功能。需要记住以下几点。

缩短应用的启动时间

当激活应用时延迟加载较大的内存中对象。如果你有大量任务需要完成,则提供一个自定义初始屏幕,以便你的应用可以在后台完成这些任务。

通过对 UI 线程使用异步 API 调用,从而强调应用的响应性能

不要使用同步 API 阻止 UI 线程。应使用异步 API 或在未阻止的上下文中调用同步 API。此外,还应该将处理密集型操作转到线程池线程。这是非常重要的,因为用户最有可能会注意到超过 100 毫秒的延迟。应该将处理密集型操作分为一系列较小的操作,从而允许 UI 线程侦听其间的用户输入。

快速呈现时使用缩略图

文件系统和媒体文件是大多数应用的重要组成部分,同时也是导致性能问题的最常见原因之一。文件访问一直是显示文件库视图的应用(如相册)的一个主要性能瓶颈。访问图像的速度可能较慢,因为这需要经过内存和 CPU 周期来储存、解码和显示图像。

不是通过缩放将全尺寸图像显示为缩略图,而是使用 Windows 运行时缩略图 API。Windows 运行时提供一组有效缓存所支持的 API,有效缓存允许应用快速获取可用作缩略图的更小版本图像。

预取缩略图

除了提供用于检索缩略图的 API 之外,Windows 运行时还在其 API 中包含了一个 SetThumbnailPrefetch 方法。该方法根据缩略图的用途、其请求的大小,以及用于检索缩略图图像的所需行为,为每个文件或文件夹指定要检索的缩略图。

在 Hilo 中,FileSystemRepository 类查询文件系统中符合特定日期条件的照片,并返回符合该条件的所有照片。CreateFileQuery 方法使用 SetThumbnailPrefetch 方法返回查询结果集中文件的缩略图。

FileSystemRepository.cpp


inline StorageFileQueryResult^ FileSystemRepository::CreateFileQuery(IStorageFolderQueryOperations^ folder, String^ query, IndexerOption indexerOption)
{
    auto fileTypeFilter = ref new Vector<String^>(items);
    auto queryOptions = ref new QueryOptions(CommonFileQuery::OrderByDate, fileTypeFilter);
    queryOptions->FolderDepth = FolderDepth::Deep;
    queryOptions->IndexerOption = indexerOption;
    queryOptions->ApplicationSearchFilter = query;
    queryOptions->SetThumbnailPrefetch(ThumbnailMode::PicturesView, 190, ThumbnailOptions::UseCurrentScale);
    queryOptions->Language = CalendarExtensions::ResolvedLanguage();
    return folder->CreateFileQueryWithOptions(queryOptions);
}


在这种情况下,该代码预取显示每个照片预览的缩略图(最大 190 像素宽),并根据显示器的每英寸像素数 (PPI) 增加请求的缩略图大小。使用 SetThumbnailPrefetch 方法可能会导致显示用户“图片”中的照片视图所花的时间缩短 70%。

调整资源字典

应用范围的资源应该存储在 Application 对象中以避免重复,但特定于单个页面的资源应该移动到该页面的资源字典中。

优化元素计数

XAML 框架设计为显示数千个对象,但减少页面上的元素数量会使你的应用呈现速度更快。你可以通过避免不需要的元素以及折叠看不到的元素来减少页面的元素计数。

使用独立动画

独立动画独立于 UI 线程运行。XAML 中使用的很多动画类型都是由在单独线程上运行的合成引擎合成的,同时该引擎的工作从 CPU 卸载到 GPU。将动画合成移动到非 UI 线程意味着动画不会抖动或者被 UI 线程上正在工作的应用阻止。在 GPU 上合成动画会大大提高性能,从而允许采用平滑且一致的帧速率运行动画。

你不需要其他标记即可使你的动画独立。系统确定可以独立合成动画的时间,但独立动画有一些限制。下面列出了一些常见的问题。

  • UIElementHeightWidth 属性设置成动画会导致从属动画,因为这些属性需要进行布局更改,而这些更改只能在 UI 线程上完成。为了拥有将 HeightWidth 设置成动画的类似效果,你可以将控件的比例设置成动画。
  • 如果你将某个元素的 CacheMode 属性设置为 BitmapCache,则可视子树中的所有动画都会采用从属方式运行。解决办法是不将缓存内容设置成动画。
  • ProgressRingProgressBar 控件拥有无限动画,即使该控件在页面上不可见,这些动画也可以继续运行,但这会阻止 CPU 进入低功耗或空闲模式。当页面上没有显示这些控件时,将 ProgressRing::IsActiveProgressBar::IsIndeterminate 属性设置为 false。

Hilo 使用 ObjectAnimationUsingKeyFrames 类型,该类型为独立动画。

针对大量计算使用平行模式

如果你的应用执行大量计算,那么你非常有可能需要使用并行编程技术。有很多既定的模式可有效使用多核硬件。使用 Microsoft Visual C++ 进行并行编程是一个用于某些最常用模式的资源,其中包含一些使用 PPL 和异步代理库的示例。有关 API 的广泛文档以及示例,请参阅并发运行时

Hilo 包含一些用于操作图像的计算密集型操作。对于这些操作,我们使用并行编程技术,该技术利用计算机的并行处理硬件。有关详细信息,请参阅本指南中的适应异步编程使用并行编程和后台任务C++ 中的异步编程模式

注意类型转换的开销

为了与 Windows 运行时功能交互,有时你需要从平台Windows 命名空间中创建数据类型。在某些情况下,创建这些类型的对象会导致类型转换的开销。Hilo 在 ABI 上进行类型转换以最大程度地减少此开销。有关详细信息,请参阅本指南中的编写现代 C++ 代码

使用封送成本最低的技术

如果你的代码使用 C++ 和 XAML 之外的语言进行通信,可能会导致在跨运行时环境对数据进行封送时产生开销。Hilo 仅使用 C++ 和 XAML 交互,因此我们不考虑这个问题。有关详细信息,请参阅本指南中的编写现代 C++ 代码

挂起时保持较低的应用内存使用率

当你的应用从挂起恢复时,它几乎可以立即重现。但当你的应用从终止重新启动时,可能需要较长的时间才能显示。因此,当应用挂起时防止应用被终止,可以使用这个方法来管理用户对应用响应性的感知和容忍。完成该操作的方法是挂起时保持较低的应用内存使用率。

当你的应用开始挂起进程时,应该释放在恢复时可以轻松重建的任何较大对象。这样做有助于保持较低的应用内存占用率,并且减少操作系统在挂起后终止应用的可能性。有关详细信息,请参阅本指南中的处理挂起、恢复和激活

通过将密集处理划分成较小的操作,从而最大程度地减少应用所使用的资源量

Windows 必须通过终止挂起的应用以允许运行其他应用,从而容纳所有 Windows 应用商店应用的资源需求。这样做的负面影响是,如果你的应用请求大量内存,那么可能会终止其他应用,即使该应用在请求之后又很快释放了该内存也是如此。我们要成为好公民,不要让用户将系统中任何感觉到的延迟归咎于你的应用。实现该目标的方法是将处理密集型操作分为一系列较小的操作。

[顶部]

 

 

显示:
© 2014 Microsoft