跳到主内容

关于性能的更多思考

什么是性能,以及为什么性能很重要

什么是性能?

#

性能是一个执行者(performer)的一组可量化属性。

在此语境下,性能指的不是动作本身的执行,而是某人或某事表现得有多好。因此,我们使用形容词 performant(高性能的)。

虽然 “表现有多好” 这一部分通常可以用自然语言描述,但在我们限定的范围内,重点在于那些可以量化为实数的事物。实数包括整数和 0/1 二进制值等特殊情况。自然语言的描述仍然非常重要。例如,一篇完全不用数字(可量化值)而仅仅用文字强烈批评 Flutter 性能的新闻文章,依然可以很有意义,并产生巨大的影响。之所以限定范围,仅仅是因为我们的资源有限。

描述性能所需的量化指标通常被称为度量标准(metric)。

为了梳理无数的性能问题和指标,你可以根据执行者进行分类。

例如,本网站的大部分内容是关于 Flutter 应用性能的,其中的执行者是 Flutter 应用。基础设施(Infra)性能对 Flutter 同样重要,执行者是构建机器人(build bots)和持续集成(CI)任务运行器:它们极大地影响了 Flutter 合并代码更改的速度,从而改善应用性能。

在这里,我们特意拓宽了范围,不仅限于应用性能问题,因为无论执行者是谁,它们都可以共享许多工具。例如,Flutter 应用性能和基础设施性能可能共享同一个仪表板和类似的报警机制。

拓宽范围也使得一些传统上容易被忽略的执行者能够被纳入考量。文档性能就是这样一个例子。执行者可以是 SDK 的 API 文档,而一个衡量指标可以是:认为该 API 文档有用的读者比例。

为什么性能很重要?

#

回答这个问题不仅对于验证性能工作至关重要,而且对于指导性能工作以使其更有用也至关重要。“为什么性能很重要?”的答案通常也是“性能如何发挥作用?”的答案。

简而言之,性能之所以重要且有用,是因为在我们的范围内,性能必须具备可量化的属性或指标。这意味着:

  1. 性能报告易于解读。
  2. 性能几乎没有歧义。
  3. 性能具有可比性和可转换性。
  4. 性能是公平的。

这并不是说非性能问题,或者不可量化的问题或描述不重要。这些要点旨在强调性能可以发挥更大作用的场景。

1. 性能报告易于解读

#

性能指标是数字。阅读数字比阅读段落容易得多。例如,工程师读出一个 1 到 5 分的性能评级可能只需要 1 秒。而阅读一份 500 字的完整反馈摘要,同一位工程师可能至少需要 1 分钟。

如果有大量数字,很容易对它们进行汇总或可视化,以便快速解读。例如,你可以通过查看直方图、平均值、分位数等,快速掌握数百万个数字的信息。如果一个指标拥有数千个数据点的历史记录,你就可以轻松绘制趋势图来查看其走向。

另一方面,如果有 n 个 500 字的文本,解读这些文本的成本几乎必然是 n 倍。分析数千条每条 500 字的历史描述是一项艰巨的任务。

2. 性能几乎没有歧义

#

将性能表现为一组数字的另一个优点是其无歧义性。当你要求动画的性能达到每帧 20 毫秒或 50 fps 时,对于这些数字,人们几乎没有误解的空间。相反,用文字描述同样的动画,有人可能称之为“好”,而另一个人可能抱怨它“很差”。同样,同一个词或短语在不同人眼中可能含义不同。你可能认为 60 fps 是“还可以”的帧率,而其他人可能认为 30 fps 才算“还可以”。

数字仍然可能存在噪声。例如,测量的每帧时间可能是该帧真正的计算时间,加上 CPU/GPU 在无关工作上花费的随机时间(噪声)。因此,指标会波动。尽管如此,数字的含义并无歧义。此外,还有严谨的理论和测试工具来处理这种噪声。例如,你可以通过多次测量来估计随机变量的分布,或者通过大数定律取多次测量的平均值来消除噪声。

3. 性能具有可比性和可转换性

#

性能数字不仅含义明确,而且比较起来也毫无歧义。例如,5 大于 4 是毋庸置疑的。另一方面,要判断“优秀(excellent)”是否比“极好(superb)”更好或更差,可能带有主观性。同样,你能确定“史诗级(epic)”是否比“传说级(legendary)”更好吗?事实上,在某些人的解读中,“强烈超出预期(strongly exceeds expectations)”可能比“极好”更好。只有在定义了映射关系(例如将“强烈超出预期”映射为 4,“极好”映射为 5)之后,它才变得无歧义且可比较。

数字还可以通过公式和函数轻松转换。例如,60 fps 可以转换为每帧 16.67 毫秒。一帧的渲染时间 x(毫秒)可以转换为二元指标 isSmooth = [x <= 16] = (x <= 16 ? 1 :0)。这种转换可以复合或链式进行,因此你可以在没有任何额外噪声或歧义的情况下,通过单一测量获得多种多样的量化指标。转换后的量化指标随后可用于进一步的比较和解读。如果你处理的是自然语言,这种转换几乎是不可能的。

4. 性能是公平的

#

如果问题的发现依赖于冗长的文字,那么那些更擅长表达(更愿意聊天或写作)的人,或者那些与开发团队联系更紧密、拥有更大沟通带宽且面对面交流成本更低的人,就会获得不公平的优势。

通过使用相同的指标来发现问题,无论用户距离多远或多么沉默,我们都能公平地对待所有问题。反过来,这使我们能够专注于那些具有更大影响力的正确问题。

如何让性能(指标)发挥作用

#

以下内容从略微不同的角度总结了此处讨论的 4 个要点:

  1. 使性能指标易于解读。不要用大量的数字(或文字)让读者感到不知所措。如果数字很多,尝试将其总结为较少的一组数字(例如,将多个数字总结为一个平均值)。仅在数字发生重大变化时通知读者(例如,针对峰值或性能回退的自动警报)。

  2. 使性能指标尽可能无歧义。定义数字所使用的单位。精确描述数字是如何测量的。使数字易于复现。当存在大量噪声时,尽量展示完整的分布,或者通过聚合大量噪声测量值来尽可能消除噪声。

  3. 使性能易于比较。例如,提供时间轴来比较当前版本与旧版本。提供将一个指标转换为另一个指标的方法和工具。例如,如果我们能将内存增长和 fps 下降都转换为用户流失数或美元形式的收入损失,那么我们就可以对它们进行比较并做出明智的取舍。

  4. 使性能指标能够监测尽可能广泛的用户群体,确保没有人被遗忘。