用户希望他们的应用保持响应,感觉自然,而不是耗尽电池。 从技术上看,性能是一项非功能要求,但将性能视为一项功能有助于实现用户的期望。 指定目标和度量结果 - 这些都是关键因素。 确定性能关键型方案,定义良好的性能含义,然后在项目的整个生命周期中尽早和经常衡量,以确保达到目标。
指定目标
用户体验是定义良好性能的基本方法。 应用的启动时间可能会影响用户对其性能的看法。 用户可能会认为应用启动时间小于 1 秒才能出色,小于 5 秒才能正常,并且超过 5 秒时会很差。
其他指标对用户体验的影响较小,例如内存。 应用在暂停或非活动时终止的可能性随活动应用使用的内存量增加而增加。 高内存使用率会降低系统上所有应用的体验,因此内存消耗目标是合理的。
设置具体且可衡量的初始目标。 它们应分为三类:
- 时间 - 用户或应用完成任务所需的时间
- 流畅性 - 应用重新绘制自身以响应用户交互的速率和连续性
- 效率 - 应用如何节省系统资源,包括电池电量
Time
考虑用户完成任务的可接受时间范围(交互类)。
| 交互类 | 用户感知 | Ideal | Maximum | 示例 |
|---|---|---|---|---|
| Fast | 最小可察觉延迟 | 100 毫秒 | 200 毫秒 | 调出应用栏;按下一个按钮(第一反应) |
| 典型 | 快速,但速度不快 | 300 毫秒 | 500 毫秒 | 调整大小;语义缩放 |
| 响应式 | 不快,但感觉响应迅速 | 500 毫秒 | 1 秒 | 导航到其他页面;恢复应用 |
| 启动 | 竞技体验 | 1 秒 | 3 秒 | 首次启动应用 |
| 连续 | 不再具有响应性 | 500 毫秒 | 5 秒 | 从 Internet 下载文件 |
| 受控 | Long;用户可以切换离开 | 500 毫秒 | 10 秒 | 从应用商店安装多个应用 |
为应用的性能场景指定交互类别。 对于每个场景,请指定应用的时间点参考、用户体验的一部分以及交互类别。
流动性
应用的特定可衡量流动性目标可能包括:
- 屏幕重绘不会出现卡顿或断续(异常)
- 动画以每秒 60 帧的速度呈现(FPS)
- 当用户平移或滚动时,应用每秒显示 3-6 页的内容
Efficiency
应用的具体可衡量效率目标可能包括:
- 应用的 CPU 占用率始终不高于目标值,且内存使用量(以 MB 为单位)也始终不高于目标值
- 当应用处于非活动状态时,CPU 和内存使用最少
- 应用可在电池电源上主动使用目标小时数
为性能设计应用
使用性能目标影响应用的设计。 请考虑以下方面:
用户界面
- 通过 优化 XAML 标记,最大程度地提高每个页面的分析和加载时间和内存效率。 延迟加载 UI 和代码,直到需要它。
- 对于
ListView和GridView,使所有项的大小相同,并使用尽可能多的 优化技术 。 - 在标记中声明 UI,而不是在代码中强制构造 UI。
- 延迟创建 UI 元素,直到用户需要使用 x:Load 属性。
- 首选主题切换和动画,而不是情节提要动画。 分镜动画需要持续刷新屏幕,并使 CPU 和图形管线保持活跃。
- 按适合其显示视图的尺寸加载图像。
CPU、内存和电源
- 将低优先级工作调度到低优先级线程上执行。 请参阅 异步编程 和 DispatcherQueue 类。
- 在不需要高开销资源(如媒体)时将其释放,以尽量减少应用的内存占用。
- 在可能的情况下,通过取消注册事件处理程序并取消引用 UI 元素来避免内存泄漏。
- 为了提高电池效率,应尽量减少轮询数据、查询传感器或在 CPU 空闲时调度任务的频率。
数据访问
- 如果可能,请预提取内容。
- 缓存访问成本高昂的内容。
- 发生缓存未命中时,应尽快显示占位界面,表明应用仍在加载内容。
性能工具
在编写代码时,添加代码,用于在应用运行时记录消息和事件。 稍后,使用分析工具(如Windows性能记录器和Windows 性能分析器(均包含在Windows Performance Toolkit中)来创建和查看有关应用性能的报告。
Windows提供Windows事件跟踪(ETW)支持的日志记录 API,提供丰富的事件日志记录和跟踪解决方案。
Windows.Foundation.Diagnostics 命名空间中的 API 包括 FileLoggingSession、LoggingActivity、LoggingChannel 和 LoggingSession 类。
// using Windows.Foundation.Diagnostics;
LoggingChannel myLoggingChannel = new LoggingChannel("MyLoggingChannel");
myLoggingChannel.LogMessage("Here's my logged message.", LoggingLevel.Information);
记录一段时间内的启动和停止事件:
LoggingChannel myLoggingChannel = new LoggingChannel("MyLoggingChannel");
LoggingActivity myLoggingActivity;
using (myLoggingActivity = new LoggingActivity("MyLoggingActivity", myLoggingChannel))
{
// A start event is logged when the activity begins.
// Add code here to do something of interest.
}
// An end event is logged when the activity ends.
对照性能目标进行测试和衡量
使用这些技巧和工具来测试你的应用与性能目标相比表现如何:
- 针对各种硬件配置进行测试,包括台式机、笔记本电脑、超极本和平板电脑。
- 针对各种屏幕大小进行测试。 更宽的屏幕显示更多内容,这可能会对性能产生负面影响。
- 消除尽可能多的测试变量:
- 在测试设备上关闭后台应用。
- 在“发布”配置中生成应用,然后将其部署到测试设备。
- 多次运行应用,以帮助消除随机测试变量并确保一致的度量。
- 测试供电能力下降情况。 用户的设备性能可能远低于你的开发机器。
- 使用Visual Studio诊断工具和Windows 性能分析器等工具的组合来衡量应用性能。
响应性能测试结果
分析性能测试结果后,确定是否需要进行任何更改:
- 是否应更改应用设计决策或优化代码?
- 是否应在代码中添加、删除或更改检测?
- 是否应修改性能目标?
如果需要更改,请进行更改,并返回到检测或测试。
Optimize
仅优化应用中的性能关键型代码路径, 这些路径花费的时间最多。 性能分析会告诉你具体是哪些区域。 通常,良好的设计实践与性能达到最高优化的代码之间往往需要权衡。 在性能不关心的领域优先考虑开发人员工作效率和良好的软件设计。