技术传播的价值,不仅仅体现在通过商业化产品和开源项目来缩短我们构建应用的路径,加速业务的上线速率,也会体现在优秀程序员在工作效率提升、产品性能优化和用户体验改善等小技巧方面的分享,以提高我们的工作能力。

从本期开始,我们将邀请来自阿里巴巴各个技术团队的程序员,涵盖中间件、前端、移动开发、大数据和人工智能等多个技术领域,分享他们在工作中的小技巧, 内容力求简短、实用和可操作。

第一期的分享嘉宾,是来自阿里巴巴中间件技术团队的程序员 - 断岭,他是阿里微服务开源项目 Dubbo 的项目组成员,也是Java线上诊断开源项目 Arthas 的负责人。

第一期:理解CPU分支预测,提高代码效率

一、基础概念:

  1. Dubbo: 是一款高性能、轻量级的开源Java RPC框架,提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现;
  2. ChannelEventRunnable: Dubbo 里所有网络事件的回调接口;
  3. JMH:即Java Microbenchmark Harness,是专门用于代码微基准测试的工具套件。在性能优化的过程中,可以使用JMH对优化的结果进行量化的分析。

二、需求缘起:

在Stack Overflow上有一个非常著名的问题:为什么处理有序数组要比非有序数组快?从问题的结论来看,是分支预测对代码运行效率的提升起到了非常重要的作用。

现今的CPU是都支持分支预测(branch prediction)和指令流水线(instruction pipeline),这俩的结合可以极大的提高CPU的工作效率,从而提高代码执行效率。但这仅适用于简单的if跳转,但对于Switch跳转,CPU则没有太好的解决办法,因为Switch本质上是据索引,是从地址数组里取地址再跳转。

三、思考和方案假设:

要提高代码执行效率,一个重要的实现原则就是尽量避免CPU把流水线清空,从Stack Overflow上的讨论结果来看,通过提高分支预测的成功率,是可以降低CPU对流水线清空的概率。那么,除了在硬件层面,是否可以考虑代码层面帮CPU把判断提前,来提高代码执行效率呢?

四、方案验证:

在Dubbo的ChannelEventRunnable里有一个Switch来判断channel state。当一个channel建立起来之后,超过99.9%的情况,它的state都是ChannelState.RECEIVED,我们可以考虑,把这个判断提前。

以下通过JMH来验证,把判断提前后是否就可以提高代码执行效率。

率。

public class TestBenchMarks {
public enum ChannelState {CONNECTED, DISCONNECTED, SENT, RECEIVED, CAUGHT    }@State(Scope.Benchmark)
public static class ExecutionPlan {@Param({ "1000000" })public int size;public ChannelState[] states = null;@Setuppublic void setUp() {ChannelState[] values = ChannelState.values();states = new ChannelState[size];Random random = new Random(new Date().getTime());for (int i = 0; i < size; i++) {int nextInt = random.nextInt(1000000);if (nextInt > 100) {states[i] = ChannelState.RECEIVED;} else {states[i] = values[nextInt % values.length];}}}
}@Fork(value = 5)
@Benchmark
@BenchmarkMode(Mode.Throughput)
public void benchSiwtch(ExecutionPlan plan, Blackhole bh) {int result = 0;for (int i = 0; i < plan.size; ++i) {switch (plan.states[i]) {case CONNECTED:result += ChannelState.CONNECTED.ordinal();break;case DISCONNECTED:result += ChannelState.DISCONNECTED.ordinal();break;case SENT:result += ChannelState.SENT.ordinal();break;case RECEIVED:result += ChannelState.RECEIVED.ordinal();break;case CAUGHT:result += ChannelState.CAUGHT.ordinal();break;}}bh.consume(result);
}@Fork(value = 5)
@Benchmark
@BenchmarkMode(Mode.Throughput)
public void benchIfAndSwitch(ExecutionPlan plan, Blackhole bh) {int result = 0;for (int i = 0; i < plan.size; ++i) {ChannelState state = plan.states[i];if (state == ChannelState.RECEIVED) {result += ChannelState.RECEIVED.ordinal();} else {switch (state) {case CONNECTED:result += ChannelState.CONNECTED.ordinal();break;case SENT:result += ChannelState.SENT.ordinal();break;case DISCONNECTED:result += ChannelState.DISCONNECTED.ordinal();break;case CAUGHT:result += ChannelState.CAUGHT.ordinal();break;}}}bh.consume(result);
}}

验证说明:

  • benchSiwtch里是纯Switch判断
  • benchIfAndSwitch 里用一个if提前判断state是否ChannelState.RECEIVED

Benchmark结果是:

Result "io.github.hengyunabc.jmh.TestBenchMarks.benchSiwtch":
576.745 ±(99.9%) 6.806 ops/s [Average]
(min, avg, max) = (490.348, 576.745, 618.360), stdev = 20.066
CI (99.9%): [569.939, 583.550](assumes normal distribution)
Run complete. Total time: 00:06:48Benchmark                         (size)   Mode  Cnt     Score    Error  Units
TestBenchMarks.benchIfAndSwitch  1000000  thrpt  100  1535.867 ± 61.212  ops/s
TestBenchMarks.benchSiwtch       1000000  thrpt  100   576.745 ±  6.806  ops/s

可以看到,提前if判断提高了近3倍的代码效率,这种技巧可以放在性能要求严格的地方。

五、总结:

  • Switch对于CPU来说难以做分支预测;
  • 某些Switch条件如果概率比较高,可以在代码层设置提前if判断,充分利用CPU的分支预测机制;

原文链接
本文为云栖社区原创内容,未经允许不得转载。

阿里程序员工作小技巧 | 理解CPU分支预测,提高代码效率相关推荐

  1. 阿里程序员工作小技巧:理解CPU分支预测,提高代码效率

    技术传播的价值,不仅仅体现在通过商业化产品和开源项目来缩短我们构建应用的路径,加速业务的上线速率,体现也会在优秀程序员在工作效率提升,产品性能优化和用户体验改善等小技巧方面的分享,以提高我们的工作能力 ...

  2. 五年程序员工作小结技巧

    因每样事物都具其特色,每个人都有其个性,故而每种工作都有其技巧,每件事情都有其方法. 程序员的工作亦是如此,假如不能抓住事物的本质去对待问题,恐事倍功半,徒劳无功. 回想起初,刚接手单片机上,简单的点 ...

  3. 转载-一个中科大差生的8年程序员工作总结 - 陈小房的文章 - 知乎

    作者:陈小房 链接:https://zhuanlan.zhihu.com/p/343098771 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 今年终于从大菊花厂离 ...

  4. 美团专家:35岁是程序员工作的终点?

    点击"开发者技术前线",选择"星标????" 在看|星标|留言,  真爱 来自:美团点评技术博客 地址:https://tech.meituan.com/stu ...

  5. 一个中科大差生的 8 年程序员工作总结

    关注.星标公众号,直达精彩内容 之前分享过一些大佬的程序人生,不少读者留言说喜欢看这类文章,因为多多少少都会对自己有一定的启发,而且也快过春节了,相信大家也没有心思看技术文章了,哈哈. 这个星期我又发 ...

  6. 程序员工作中沟通能力重要吗

    大家都知道,一个IT程序员在工作中技术能力,知识积累很重要,很多人不解,我把工作做好了,功能开发出来了,网站搭建好了就可以了啊,为什么还需要沟通能力呢,今天,小编就给大家介绍下程序员工作中沟通能力重要 ...

  7. 程序员工作经验谈之商贸平台

    程序员工作经验谈 1.怎样顺利找到工作,并稳稳当当坐下来呢? ①如何通过面试? 答:态度要积极,要听话.积极并且有热情. 表达能力要良好,能够流利介绍个人情况,例如工作情况,为何离职等. 专业基础要扎 ...

  8. 程序员工作五年之后,我转行成为公务员,分享一下切身体会

    程序员工作了五年之后,我参加了公务员考试,如今我已经在新的岗位工作中有两年了.我想分享一下我这两年的感受.这是兴哥粉丝小罗的一段真实的经历,大家一起听一下他的自述. 首先,适应期在第一年,第二年我完全 ...

  9. 程序员工作不稳定?你以为的稳定工作,其实都是高风险职业

    你一定听到过别人这样的议论: "程序员工作太不稳定,天天总跳槽,而且年龄越大越不吃香...." 今天笔者来带大家算一笔账,看看他们口中稳定的职业,和"程序员"不 ...

最新文章

  1. Fiddler无法抓取HTTPS的问题,Fiddler证书无法安装终极解决方案,
  2. “裁员” + 滤镜 = “毕业”
  3. JetBrains 加入 .NET 基金会
  4. ADO连接各种数据库
  5. android:configChanges属性
  6. 2013,HTML5将席卷国内互联网
  7. (转)Rust :文件分层
  8. 啸叫抑制(howling suppression)
  9. 游程编码压缩及解压缩
  10. UART BootROM
  11. 安排几款实用的内网穿透工具(加教程)
  12. vue3+vant开发微信公众号网页爬坑不完全指北
  13. 初试Android原生弹窗
  14. Vue ajax跨域请求*
  15. 正则 环视 oracle,环视正则 - travler的个人空间 - OSCHINA - 中文开源技术交流社区...
  16. 动手吧,vue移动端悬浮球组件
  17. LeetBook哈希表专题题解(详解/一题多解)
  18. win7自动关机命令(win7设置每天自动关机命令)
  19. mysql installer 下载_MySQL Installer
  20. java 流程引擎_java工作流引擎Jflow父子流程demo

热门文章

  1. 网页中竖的目录怎么改成横的_怎么学习手绘插画?小白也能入门哦
  2. yolo极大抑制_pytorch实现yolov3(4) 非极大值抑制nms
  3. mysql如何定位耗时较长的sql_Mysql实例mysql优化之定位效率较低的SQL
  4. 十二月份找工作好找吗_小儿推拿师工作好找吗?工资高吗?
  5. redis延迟队列 实现_灵感来袭,基于Redis的分布式延迟队列
  6. 数学领域的世界顶级大佬们都在做什么科研项目?
  7. ​【文末有福利】股票跨度——真实世界的算法
  8. 上海交大25岁博士奶爸!6块腹肌,Science一作,人民日报都点赞了
  9. 【TensorFlow】学习资源汇总以及知识总结
  10. Linux下environ环境变量操作函数