关于后端:是什么让一段20行代码的性能提升了10倍

31次阅读

共计 3317 个字符,预计需要花费 9 分钟才能阅读完成。

简介:性能优化不言而喻的益处是可能节约机器资源。如果一个有 2000 台服务器的利用,整体性能晋升了 10%,实践上来说,就相当于节俭了 200 台的机器。除了节俭机器资源外,性能好的利用绝对于性能差的利用,在应答流量突增时更不容易达到机器的性能瓶颈,在同样流量场景下进行机器扩容时,也只须要更少的机器,从而可能更快的实现扩容、应急操作。所以,性能好的利用绝对于性能差的利用在稳定性方面也更胜一筹。

作者 | 金盛杰 (司旭) 起源 | 阿里开发者公众号一、背景 1.1 业务背景支付宝卡包寄存着用户的会员卡和优惠券。无论是卡券 cell,还是卡券详情,都是通过动态模板配置加上动静可变数据,最终出现给终端用户的。上面【图 1】展示了卡券数据在 C 端用户的展示模式,【图 2】示意了 C 端数据组装过程。

【图 1】卡券数据在 C 端展示模式

【图 2】C 端数据组装过程 以【图 2】为例,模板中有 availableAmount 和 voucherName 两个变量,这两个变量在动静变量数据有对应的值。用动静的值替换掉模板外面对应的这两个变量,最初拼装成“100 元红包名称”。当这个红包被应用了一次,生产了 30 元后,动态数据外面 availableAmount 的值就会变成 70。用户再次进入到红包详情页时,展示数据从新组装后就会变成“70 元红包名称”。1.2 问题发现最近做我的项目过程中,把卡券组装渲染逻辑好好的梳理了一遍,其中认真研读了【图 3】这段模板变量替换逻辑。这是一段老代码,从卡包产品诞生之日起就存在,差不多有十年的工夫了。其作用就是用动态数据替换掉模板外面的变量。这段代码逻辑咋一看,并没有什么问题,就是把模板外面两个 $ 之间(蕴含)的变量,用动态数据进行替换。思考到这是一段极为外围又高频的调用逻辑,于是看看有没有性能优化的空间。

【图 3】模板变量替换代码实现 把替换逻辑厘清了之后,第一感觉就是这段代码有性能晋升的空间。次要有两点:1、每次 while 循环进行了两次 indexOf 操作 2、每次 while 循环都进行了 substring 操作于是,就有了上面两个疑难:1、可能缩小 indexOf 和 substring 操作吗?2、真的每次都要进行模板变量查找吗?二、性能优化带着下面两个问题,逐渐进行性能优化并测试。整个优化过程一共迭代了 5 版,并最终获得了性能晋升超过 10 倍的成果。上面别离来介绍下不同版本的实现和性能比照。2.1 性能优化 V1 这一版去掉了 indexOf 和 substring 操作,转而应用另一种替换形式。之前的替换逻辑是从头到尾循环模板内容字符串,遇到 $ 之间的变量就进行替换,过程中须要一直的进行 indexOf 和 substring 操作。新的实现形式是在进行变量替换之前,通过循环模板内容字符串,利用双指针把模板外面所有变量都提取进去,再对变量汇合进行循环,顺次替换掉模板内容外面的变量。

【图 4】性能优化 V1 代码实现 2.2 性能优化 V2 动态模板配置个别状况下不会产生变更。也就意味着,同一个模板对应的变量都是固定不变的。能够将模板 id 和模板变量汇合进行一对一的缓存,缩小每次替换之前的变量提取。在决定应用缓存之前,要想好怎么实现缓存。有两点须要留神:1、用本地缓存代替 TBase,缩小大流量场景下对 TBase 的压力 2、怎么管制本地缓存的无效数量,并在无限的内存占用状况下最大化缓存效率能够借助 Google Guava 库的缓存类来实现缓存逻辑,示例代码见【图 5】

【图 5】缓存实现示例代码 

【图 6】性能优化 V2 代码实现 2.3 性能比照 (1)做完下面两步之后进行了性能测试,性能对比方【图 7】所示。

【图 7】V1、V2 版性能比照 通过性能比照发现,V1 版绝对于原始版有性能晋升,带缓存的 V2 版绝对于不带缓存的 V1 版也有性能晋升。但随着流量增大,性能优化成果逐渐削弱。阐明 V1、V2 版耗时优化的点,在整个模板变量替换耗时中占比并不高。也同时阐明,整个模板变量替换逻辑当中,还存在其余更为耗时的点。回过头来再认真看一遍变量替换逻辑,忽然间意识到脱漏了一个”大问题“。就是这个 String.replace 办法,该办法有两个耗时点:1、每次 replace 都会进行模板编译 2、replace 都是创立一个新的对象进行返回并且每次 replace 之后还要进行变量的从新赋值。

【图 8】String.replace 代码实现 2.4 性能优化 V3 在 V2 版根底上,去掉 replace 办法,用 StringBuilder 来实现。

【图 9】性能优化 V3 代码实现 StringBuilder 实现过程中有一点要留神。V2 版本中,提取变量返回的是一个 Set 汇合。返回汇合中呈现变量的程序和模板中变量程序会不统一,模板中有多个雷同变量的状况下,也只会替换第一个呈现的变量。所以要将变量提取返回的后果换成有序可反复的 List,能力保障逻辑的正确性。2.5 性能优化 V4V3 版优化之后,性能晋升显著,证实 String.replace 办法才是整个模板变量替换逻辑中最为耗时的点。于是在原办法上只用 StringBuilder 来替换 String.replace,失去 V4 版。

【图 10】性能优化 V4 代码实现 2.6 性能比照(2)

【图 11】V1、V2、V3、V4 版性能比照 通过【图 11】能够显著的发现,在进行 StringBuilder 实现后,性能晋升超过 10 倍,成果非常显著。V4 版耗时实际上比 V3 版带缓存的还要少,阐明 V3 版先提取变量再进行 StringBuilder 组装的过程,相对来说还是会更耗时一点。但 V4 版的代码可读性是不如 V3 版的,能够把 V3 版和 V4 版相结合,剔除掉缓存依赖,产生一个代码可读性和性能最佳的 V5 版。2.7 性能优化 V5 先提取变量,去掉缓存依赖,用 StringBuilder 替换掉 String.replace,减少代码可读性。

【图 12】V5 版代码实现 &100 万次循环耗时比照 三、总结通过下面 5 个版本的性能优化,性能失去了超过 10 倍的晋升。性能由高到低的程序是 V4 > V3 > V5 > V2 > V1 > 未被优化的原始版。其中 V3、V4、V5 版的性能显著优于 V1 和 V2 版,证实这段模板替换逻辑最为耗时的点为 String.replace,V3 > V5 和 V2 > V1 表明,引入缓存对性能晋升还是有肯定帮忙的。在代码可读性方面,V4 是不如 V3 和 V5 的。整个优化总结下来次要有两点:1、String.replace 办法波及到模板编译和新字符串生成,比拟吃资源 2、StringBuilder 代替 String.replace,除了可能缩短调用耗时,在空间上也可能缩小资源占用。因为 StringBuilder.append 绝对于 String.replace 来说,可能缩小两头大量 String 对象的创立和销毁,可能缩小 GC 的压力,从而升高 CPU 的负载。性能优化不言而喻的益处是可能节约机器资源。如果一个有 2000 台服务器的利用,整体性能晋升了 10%,实践上来说,就相当于节俭了 200 台的机器。除了节俭机器资源外,性能好的利用绝对于性能差的利用,在应答流量突增时更不容易达到机器的性能瓶颈,在同样流量场景下进行机器扩容时,也只须要更少的机器,从而可能更快的实现扩容、应急操作。所以,性能好的利用绝对于性能差的利用在稳定性方面也更胜一筹。最初再回到本次文章的主题:是什么让一段 20 行代码的性能晋升了 10 倍?我的答复是:StringBuilder yyds!举荐浏览 1. 代码圈复杂度治理小结 2. 如何写出无效的单元测试 3. java 利用提速(速度与激情)《低代码引擎技术白皮书》低代码引擎是一款为低代码平台开发者提供的,具备弱小定制扩大能力的低代码设计器研发框架。本书从利用、根底协定和原理三个方面对低代码引擎的技术进行了全面的介绍,并在低代码引擎原理篇重点介绍了低代码引擎所需的渲染、入料、编排、出码等核心技术原理,对低代码引擎的生态设计进行了介绍。本书适宜于有低代码产品研发诉求的前端开发人员。点击这里,查看详情。原文链接:https://click.aliyun.com/m/10… 本文为阿里云原创内容,未经容许不得转载。

正文完
 0