客户端敏捷开发之道【三】:性能优化篇

发表于2016-12-05
评论0 1.41w浏览
  正式参加工作已逾三年,打算把工作沉淀下来的方法论整理出来,以作纪念。思来想去,还是觉得用「敏捷之道」贯穿这个系列最为合适。由于每年新沉淀的方法论,是在以往的经验基础上总结的,因此本系列文章具有一定的前后依赖关系,建议按顺序阅读。
  本文将会总结三条性能优化的通用方法,根据它们的优化策略,可以分为:
  战法级优化法、战术级优化法、战略级优化法

(一)战法级性能优化法
  前些年曾经看到过一篇报道,德国的工程师在工作之余会精心擦拭和保养自己的工具。扳手、螺丝刀一应俱全,我一直觉得这是个不得了的好习惯,工欲善其事,必先利其器。
  战法优化一种非常直接的性能优化方法:使用工具 → 定位问题 → 解决问题。

定位性能消耗的分析工具有两类比较常用:
  第一类是以BenchMark方式为主的打点耗时分析。一般需要手动在代码里打点。
  第二类是在运行时抽样调查CPU执行函数,用于分析哪个函数耗时更长的工具。例如Windows平台下的WPFPerf,Android平台下的TraceView。

是不是加个图看起来会高端一点:WPFPerf Performance Profiling Tools

  通过打点分析工具,找到性能消耗比较大的函数。如果是I/O操作放到界面线程,那么就把I/O操作异步加载。如果是发现算法太过复杂,那么优化算法即可。

(二)战术级性能优化法
  我们发现,很多时候常规的性能优化并不能解决问题,甚至会陷入死循环,比如二级页面觉得自己加载速度慢,就把一堆操作放到一级页面。一级页面觉得自己慢,又把一堆操作塞回二级页面。这时我们需要站在更高的维度来思考性能优化的问题。
  所谓的战术级性能优化法是一种思考问题的方法:站在整个系统的角度,思考性能最优解。
  前段时间做一个功能,需要将XML文件,解析还原成指定界面代码,通过后台下发配置XML配置,这个功能对于时间要求非常高。
  在实现这个功能的过程中遇到了一个非常麻烦的问题,解析XML非常耗时!一个简单的解析耗时800ms,也就意味着说,点击一个页面1秒以上才有反应,这是绝对不可接受的。经过上文的战法级优化,已经把耗时操作全部解决掉,加载速度依然有200ms。在这个case下,解析XML的操作是绝不可能去掉的,而解析XML的时间也没什么优化空间。
  这时该考虑的问题是:整个加载过程的最优解是什么?
  为什么Android的XML可以快速解析,一个很重要的原因是Android的XML被解析成了二进制文件,加载速度飞快。那我们如果把XML也解析成二进制数据保存到内存中,是不是更快了?
  也就是说,只必须要在界面线程的操作才保留在界面线程,其他操作全部放到工作线程预加载。顺着这个思路,我们把XML解析的操作放到工作线程中预加载,必须要在界面线程的操作才放到界面线程。最终这次性能优化将加载速度从800ms优化到了20ms。
  在这个case下,力求将终端的CPU利用率最大化,以达到性能诉求的充分满足。
  战法和战术的区别在于:前者碰到问题解决问题,而后者从最理想状况反推解决方案,力求在当前case下彻底解决问题。

(三)战略级性能优化法
  前段时间罗辑思维节目关于什么是战略的解释是:战略是从一个平衡过度到另一个平衡。
  有时,即使采用所谓的最优解思路,仍然无法解决问题。例如某需求需要将一次网络请求降到10ms。在这类case下,我们需要跳出圈子思考。
  loading其实就是非常好的这类优化应用,不妨拆解一下loading的思考过程。
  需求:网络请求降低到10ms。无法将网络请求降低到这么低,为什么要降低到10ms?因为网络请求过慢导致用户流失。为什么用户流失?因为用户产生了焦虑情绪。能否用其他方式化解用户焦虑?可以用loading告知用户加载中。


  跳出圈子思考问题是指,在已有解决方案无法满足的情况下,思考为什么要做这件事情。这件事情有没有其它解决方案。如果还没有,就再从更高的角度思考,如何解决这个问题。
  在这个case下,我们并没有解决问题,只是缓解问题带来的负面影响。试想,如果使用loading可以大幅度降低用户流失,那是不是和加载速度达到非常快,意义是基本相同的呢。

(四)吾生也有涯,性能也无涯,以有涯随无涯,殆已
  性能优化是个无止境的过程,一般来说,当我们过于追逐后20%的性能时,将会消耗多过80%的精力。正如上一篇所述,性能的优化是以满足用户诉求为目标,而不是以无止境的优化为目标。因此性能优化应当本着达标就好的原则。将结构设计的足够简单,当真正出现性能问题时,才知道如何下手,而将框架改造的极其复杂以满足微量的性能提高是不可取的。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引