用户希望他们的应用保持响应,感觉自然,而不是耗尽电池。 从技术上看,性能是一项非功能要求,但将性能视为一项功能将帮助你实现用户的期望。 指定目标和度量是关键因素。 确定性能关键型方案是什么;定义良好的性能含义。 然后,在项目的整个生命周期内提前且频繁地衡量,以确保达到目标。
指定目标
用户体验是定义良好性能的基本方法。 应用的启动时间可能会影响用户对其性能的看法。 用户可能会认为应用启动时间小于 1 秒是优秀的,小于 5 秒是好的,并且大于 5 秒要差。
其他指标对用户体验的影响较小,例如内存。 在暂停或非活动时终止应用的可能性会随着活动应用使用的内存量而增加。 这是一般规则,高内存使用率会降低系统上所有应用的体验,因此,对内存消耗有一个目标是合理的。 考虑用户认为应用的粗略大小:小、中或大。 对性能的期望将与这种感知相关。 例如,你可能希望一个小应用不使用大量媒体来消耗少于 100MB 的内存。
最好设定一个初始目标,然后修改它,而不是根本不有一个目标。 应用的性能目标应是具体且可衡量的,它们应分为三类:用户或应用完成任务所需的时间(时间):应用重新绘制自身以响应用户交互的速率和连续性(流畅性):应用如何节省系统资源,包括电池电量(效率)。
时间
考虑用户在你的应用中完成任务所需的可接受时间范围(交互类)。 对于每个交互类,请分配一个标签、一个感知的用户情绪,以及理想和最长持续时间。 下面是一些建议。
交互类标签 | 用户感知 | 理想 | 最大值 | 例子 |
---|---|---|---|---|
快速 | 最小可察觉的延迟 | 100 毫秒 | 200 毫秒 | 打开应用栏,并按下按钮(第一个响应) |
典型 | 迅速,但不够快 | 300 毫秒 | 500 毫秒 | 调整大小;语义缩放 |
响应式 | 不够快捷,但感觉反应灵敏 | 500 毫秒 | 1 秒 | 导航到其他页面;从挂起状态恢复应用 |
发射 | 竞争体验 | 1 秒 | 3 秒 | 首次启动应用或之前终止后再次启动应用 |
连续的 | 感觉不再灵敏 | 500 毫秒 | 5 秒 | 从 Internet 下载文件 |
俘虏 | 时间长; 用户可能会离开 | 500 毫秒 | 10 秒 | 从应用商店安装多个应用 |
现在可以将交互类分配给应用的性能场景。 可以为每个方案分配应用的时间点引用、用户体验的某一部分和交互类别。 下面是有关示例食品和餐饮应用的一些建议。
情景 | 时间点 | 用户体验 | 交互类 |
---|---|---|---|
导航到食谱页 | 第一个响应 | 页面切换动画已启动 | 快速 (100-200 毫秒) |
响应式 | 成分列表已加载,无图像 | 响应(500 毫秒 - 1 秒) | |
可见状态:已完成 | 所有内容已加载;图像已显示 | 连续 (500 毫秒 - 5 秒) | |
搜索食谱 | 第一个响应 | 已单击“搜索”按钮 | 快速 (100 - 200 毫秒) |
可见状态:已完成 | 显示的本地食谱标题列表 | 典型 (300 - 500 毫秒) |
如果要显示实时内容,则还要考虑内容新鲜度目标。 目标是每隔几秒钟刷新内容一次? 或者每隔几分钟、每隔几小时甚至每天刷新一次内容是可接受的用户体验吗?
指定目标后,现在可以更好地测试、分析和优化应用。
流动性
应用的特定可衡量流动性目标可能包括:
- 屏幕重新绘制时没有停顿和闪烁(故障)。
- 动画以每秒 60 帧(FPS)呈现。
- 当用户平移/滚动时,应用每秒显示 3-6 页的内容。
效率
应用的具体可衡量效率目标可能包括:
- 对于应用的进程,CPU 百分比始终不超过 N,内存使用量(以 MB 为单位)始终不超过 M。
- 当应用处于非活动状态时,你的应用进程中的 N 和 M 均为零。
- 你的应用可以使用 X 小时的电池电量,当你的应用处于非活动状态时,设备将保留 Y 小时的电量。
为性能设计应用
现在可以使用性能目标来影响应用的设计。 使用示例食品和餐饮应用,在用户导航到食谱页面后,可以选择 以增量方式更新项目,以便首先呈现食谱的名称,显示成分延迟,并进一步显示图像。 这会在平移/滚动的同时保持响应能力和流畅 UI,在交互速度变慢后进行完全保真呈现,使 UI 线程能够赶上。 下面是需要考虑的一些其他方面。
用户界面
- 通过 优化 XAML 标记,最大程度地提高应用的 UI 的每个页面(尤其是初始页面)的分析和加载时间和内存效率。 简言之,延迟加载 UI 和代码,直到需要它。
- 对于 ListView 和 GridView,使所有项的大小相同,并尽可能多地使用 ListView 和 GridView 优化 技术。
- 以标记形式声明 UI,框架可以在区块中加载和重复使用,而不是在代码中强制构造 UI。
- 延迟创建 UI 元素,直到用户需要它们。 请参阅 x:Load 属性。
- 首选主题切换和动画,而不是情节提要动画。 有关详细信息,请参阅 动画概述。 请记住,故事板动画需要不断更新屏幕,以保持 CPU 和图形管道的活动状态。 若要保留电池,如果用户不与应用交互,则不要运行动画。
- 应使用 GetThumbnailAsync 方法,将图像加载为适合其呈现视图的大小。
CPU、内存和电源
- 计划优先级较低的工作,以在低优先级线程和/或核心上运行。 请参阅 异步编程、Dispatcher 属性和 CoreDispatcher 类。
- 通过在暂停时释放昂贵的资源(如媒体),最大程度地减少应用的内存占用。
- 最大程度地减少代码的工作集。
- 尽可能取消注册事件处理程序和取消引用 UI 元素,避免内存泄漏。
- 为了节省电池,慎重安排轮询数据、查询传感器及在 CPU 空闲时计划工作。
数据访问
- 如果可能,请预提取内容。 有关自动预提取,请参阅 ContentPrefetcher 类。 有关手动预提取,请参阅 Windows.ApplicationModel.Background 命名空间和 MaintenanceTrigger 类。
- 如果可能,缓存访问成本高昂的内容。 请参阅 LocalFolder 和 LocalSettings 属性。
- 对于缓存未命中的情况下,请尽快显示一个占位符界面,指示应用仍在加载内容。 在从占位符过渡到实时内容时,应以不会导致用户感到突兀的方式进行。 例如,当应用加载实时内容时,不要更改用户手指或鼠标指针下的内容的位置。
应用启动和恢复
- 延迟应用的启动屏幕,除非必要,否则不要延长应用的启动屏幕。 有关详细信息,请参阅 创建快速流畅的应用启动体验 和 显示初始屏幕以延长显示时间。
- 禁用在关闭初始屏幕后立即发生的动画,因为这些动画只会导致对应用启动时间延迟的感知。
自适应用户界面和方向
- 使用 VisualStateManager 类。
- 只需立即完成所需的工作,将密集型应用工作推迟到以后—你的应用在用户看到应用 UI 处于裁剪状态之前,需要 200 到 800 毫秒才能完成工作。
借助与性能相关的设计,可以开始对应用进行编码。
性能工具
在编写代码时,添加代码,用于在应用运行时记录消息和事件。 稍后,在测试应用时,可以使用分析工具(如 Windows 性能记录器和 Windows 性能分析器(这两者都包含在 Windows Performance Toolkit)来创建和查看有关应用性能的报告。 在此报表中,你可以查找这些消息和事件,以帮助你更轻松地分析报表的结果。
通用 Windows 平台(UWP)提供日志记录 API,由 Windows 事件跟踪(ETW)提供支持,同时提供丰富的事件日志记录和跟踪解决方案。 API 属于 Windows.Foundation.Diagnostics 命名空间,包括 FileLoggingSession、LoggingActivity、LoggingChannel和 LoggingSession 类。
若要在应用运行时在特定时间记录报表中的消息,请创建一个 LoggingChannel 对象,然后调用对象的 LogMessage 方法,如下所示。
// using Windows.Foundation.Diagnostics;
// ...
LoggingChannel myLoggingChannel = new LoggingChannel("MyLoggingChannel");
myLoggingChannel.LogMessage(LoggingLevel.Information, "Here' s my logged message.");
// ...
若要在应用运行时记录报表中的启动和停止事件,请创建 LoggingActivity 对象,然后调用对象的 LoggingActivity 构造函数,如下所示。
// using Windows.Foundation.Diagnostics;
// ...
LoggingActivity myLoggingActivity;
// myLoggingChannel is defined and initialized in the previous code example.
using (myLoggingActivity = new LoggingActivity("MyLoggingActivity"), myLoggingChannel))
{ // After this logging activity starts, a start event is logged.
// Add code here to do something of interest.
} // After this logging activity ends, an end event is logged.
// ...
另请参阅 日志记录示例。
通过对应用进行监控设置后,您可以测试和测量应用的性能。
测试并衡量性能目标
性能计划的一部分是在开发期间定义度量性能的点。 这适用于不同的目的,具体取决于是在原型制作、开发还是部署期间进行测量。 在原型制作早期阶段测量性能可能非常有价值,因此,建议在代码执行有意义的工作后立即执行此操作。 早期的评估可以很好地了解您应用中的重要成本,并为设计决策提供参考。 从而实现高性能和可扩展的应用程序。 在后期更改设计通常比在早期更改更昂贵。 在产品周期后期测量性能可能会导致最后一刻的黑客攻击和性能不佳。
使用这些技术和工具测试应用如何与原始性能目标相媲美。
- 针对各种硬件配置进行测试,包括一体机和台式电脑、笔记本电脑、超笔记本、平板电脑和其他移动设备。
- 针对各种屏幕大小进行测试。 虽然更宽的屏幕大小可以显示更多内容,但引入所有这些额外内容可能会对性能产生负面影响。
- 尽可能消除任意数量的测试变量。
- 在测试设备上关闭后台应用。 为此,在 Windows 中,从“开始”菜单 >>中选择 设置。 选择每个活动应用,然后选择 无。
- 在将应用部署到测试设备之前,在发布配置中生成应用,将其编译为本机代码。
- 为了确保自动维护不会影响测试设备的性能,请手动触发它并等待它完成。 在 Windows 的“开始”菜单中,搜索 安全和维护。 在 维护 区域中,在 自动维护下,选择 启动维护 并等待状态从正在进行的 维护更改。
- 多次运行应用以帮助消除随机测试变量,并帮助确保一致的度量。
- 测试电力供应减少的情况。 您用户的设备可能比您的开发计算机的处理能力低得多。 Windows 设计时考虑到了低功率设备(如移动设备)。 在平台上运行的应用应确保它们在这些设备上表现良好。 预计低功率设备的运行速度是台式计算机的大约四分之一,并据此设定目标。
- 使用 Microsoft Visual Studio 和 Windows Performance Analyzer 等工具的组合来度量应用性能。 Visual Studio 旨在提供以应用为中心的分析,例如源代码链接。 Windows Performance Analyzer 旨在提供以系统为中心的分析,例如提供系统信息、有关触摸操作事件的信息,以及有关磁盘输入/输出(I/O)和图形处理单元(GPU)成本的信息。 这两种工具都提供跟踪捕获和导出,并且可以重新打开共享跟踪和事后跟踪。
- 在将应用提交到应用商店进行认证之前,请务必将性能相关的测试用例纳入测试计划,如 Windows 应用认证工具包测试 的“性能测试”部分和 UWP 应用测试用例的“性能和稳定性”部分中所述。
有关详细信息,请参阅这些资源和分析工具。
- Windows 性能分析器
- Windows 性能工具包
- 使用 Visual Studio 诊断工具分析性能
- //build/ 会话 XAML 性能
- Visual Studio 2015 中的 //build/session New XAML Tools
响应性能测试结果
分析性能测试结果后,确定是否需要进行任何更改,例如:
- 是否应更改任何应用设计决策或优化代码?
- 是否应该在代码中添加、删除或更改任何仪器?
- 是否应修改任何性能目标?
如果需要任何更改,请进行更改,然后继续进行调试或测试,然后重复这个过程。
优化
仅优化应用程序中性能关键的代码路径:即程序执行时花费最多时间的地方。 分析将告诉你是哪一个。 通常,创建遵循良好设计做法的软件和编写以最高优化方式执行的代码之间存在权衡。 通常,在性能不重要的领域,优先考虑开发人员的工作效率和良好的软件设计会更好。