【C# 线程】编译器代码优化技术 循环提升:Loop Hoisting
转载自:https://gandalfliang.github.io/2019/01/15/loop-hoisting/
Loop Hoisting
在上篇文章中,提到 Loop Hoisting ,这是一个常见的编译器优化项。我们总是能通过汇编代码等低级语言来“窥探”代码实际是怎么“指示”硬件运行的(这边文章不会涉及到详细的汇编内容,但是会用C#反编译后得到的汇编代码来辅助说明)。如果你看过我前面的几篇文章,会发现我用了大量反编译后的汇编代码来辅助说明,毕竟,千言不如实际的“证据”有说服力。
言归正传,Loop Hoisting,循环提升(粗略的翻译),编译器对循环代码中 loop-invariant 的代码提取出循环体外,防止循环结构内CPU对主存的重复读取。这很好理解,减少 CPU 与主存之间的 IO 次数,能有效提升程序的运行效率。观察下面的例子:
namespace loop_hoisting
{
class Program
{
static void Main(string[] args)
{
int[] array = new int[] { 1, 2, 3 };
int x = 10;
int y = 11; LoopHoistTest(array, x, y);
} static void LoopHoistTest(int[] array, int x, int y)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = x + y;
}
}
}
}
很简单的一个例子,遍历列表且赋值。LoopHoistTest 函数的循环判断里,直接读取列表的长度,编译器在碰到这种情况,会对其进行优化,将对列表长度的读取进行提升(Hoist),在循环体入口处缓存列表长度,并以此为判断依据,也就是说,从汇编代码的角度,循环判断始终去寄存器中读取缓存的列表长度信息,而不是每次都到主存中读取,以此来提到运行效率。另外,x+y很明显也是一段 loop-invariant 代码,相似地,编译器会将 x+y 的值缓存在某个通用寄存器内,并以此做赋值运算。编译器优化后的代码,就相当于:
namespace loop_hoisting
{
class Program
{
static void Main(string[] args)
{
int[] array = new int[] { 1, 2, 3 };
int x = 10;
int y = 11; LoopHoistTest(array, x, y);
} static void LoopHoistTest(int[] array, int x, int y)
{
int length = array.Length;
int sum = x+y; for (int i = 0; i < length; i++)
{
array[i] = sum;
}
}
}
}
观察汇编代码:

第一个红色框选的汇编代码:
mov ebx,dword ptr [rsi+8] //将rsi寄存器值加上8的偏移量指向的主存中的值复制到ebx通用寄存器
其中rsi寄存器中的值就是主存中array的地址,偏移的8位指向length字段,这段指令将数值中的长度信息储存在ebx通用寄存器中,并且在以后的cmp指令中使用,而不是直接与主存中的内容比较。
lea ebp,[rdx+r8] //将 rdx 和 r8 寄存器中的值相加并传送到 ebp 寄存器
其中,rdx和r8寄存器分别储存着 x 和 y 的值,两者的和被储存在ebp寄存器,以后的指令都使用这个寄存器中的值,不再重复计算。
当然,并不是所有的循环代码都可以被优化,这涉及到 Loop-invariant 条件的判定,我们下篇文章再讲。
【C# 线程】编译器代码优化技术 循环提升:Loop Hoisting的更多相关文章
- Looper.loop() android线程中的消息循环
Looper用于封装了android线程中的消息循环,默认情况下一个线程是不存在消息循环(message loop)的,需要调用Looper.prepare()来给线程创建一个消息循环,调用Loope ...
- 简单了解一下事件循环(Event Loop)
关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...
- 事件循环Event loop到底是什么
摘要:本文通过结合官方文档MDN和其他博客深入解析浏览器的事件循环机制,而NodeJS有另一套事件循环机制,不在本文讨论范围中.process.nextTick和setImmediate是NodeJS ...
- TMsgThread, TCommThread -- 在delphi线程中实现消息循环
http://delphi.cjcsoft.net//viewthread.php?tid=635 在delphi线程中实现消息循环 在delphi线程中实现消息循环 Delphi的TThread类使 ...
- TMsgThread, TCommThread -- 在delphi线程中实现消息循环(105篇博客,好多研究消息的文章)
在delphi线程中实现消息循环 在delphi线程中实现消息循环 Delphi的TThread类使用很方便,但是有时候我们需要在线程类中使用消息循环,delphi没有提供. 花了两天的事件研究了 ...
- 心智与认知(1): 反馈循环(Feedback loop)
目录: ** 0x01 反馈循环(Feedback loop) | How to see System in everyday life ** 0x02 如何像视频游戏一样剖析你的人生?| 打怪升级这 ...
- JS事件循环(Event Loop)机制
前言 众所周知,为了与浏览器进行交互,Javascript是一门非阻塞单线程脚本语言. 为何单线程? 因为如果在DOM操作中,有两个线程一个添加节点,一个删除节点,浏览器并不知道以哪个为准,所以只能选 ...
- 事件循环 event loop 究竟是什么
事件循环 event loop 究竟是什么 一些概念 浏览器运行时是多进程,从任务管理器或者活动监视器上可以验证. 打开新标签页和增加一个插件都会增加一个进程,如下图:  浏览器渲染进程是多线程,包 ...
- oracle的控制语句if和循环语句loop while for
pl/sql的控制结构if-then if-then-else if-then-elsif-else 案例1:编写一个过程,可以输入一个雇员名,如果该雇员的工资低于2000,就给该雇员工资增加10% ...
随机推荐
- Choregraphe 2.8.6.23虚拟Nao机器人Socket is not connected
Traceback (most recent call last): File "c:/Users/fengmao/OneDrive - University of Wollongong/J ...
- log4j学习记录以及相关配置(精简版)
使用log4j时关键配置 log4j的maven依赖 <dependency> <groupId>log4j</groupId> <artifactId> ...
- Asp-Net-Core学习笔记:身份认证入门
前言 过年前我又来更新了~ 我就说了最近不是在偷懒吧,其实这段时间还是有积累一些东西的,不过还没去整理-- 所以只能发以前没写完的一些笔记出来 就当做是温习一下啦 PS:之前说的红包封面我还没搞,得抓 ...
- JavaScript之Promise实现原理(手写简易版本 MPromise)
手写 Promise 实现 Promise的基本使用 Promise定义及用法详情文档:Promise MAD文档 function testPromise(param) { return new P ...
- Vue+webpack配置实现多页面应用开发
为什么要配置多页面开发? · 由于单页面应用不利于SEO,对于某些资讯类网站不够友好,而多页面则能够更优的解决此问题. · 传统的多页面开发模式(如java的jsp等) 前后端耦合性大,开发效率低,代 ...
- ApacheCN 深度学习译文集 20201229 更新
新增了七个教程: TensorFlow 和 Keras 应用开发入门 零.前言 一.神经网络和深度学习简介 二.模型架构 三.模型评估和优化 四.产品化 TensorFlow 图像深度学习实用指南 零 ...
- Programiz 中文系列教程·翻译完成
原文:Programiz 协议:CC BY-NC-SA 4.0 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远. 在线阅读 ApacheCN 学习资源 目录 Programiz C ...
- 关于https域名下的页面iframe嵌套http页面的问题
业务场景:在一个https域名下用iframe嵌套一个http域名的页面,会直接报错的,报错信息如下: 这段话的意思是:http域名的页面是通过https域名页面加载的,在一个安全的页面不允许加载一个 ...
- 深坑react 引入antd无效问题
//安装babel-plugin-import 第一步:npm install babel-plugin-import --save第二步:暴露webpack.config.js运行:npm run ...
- NSDate分类,把系统返回的时间与现在进行比较---秀清
// // NSDate+Joe.h // WeiBo // // Created by 张秀清 on 15/9/17. // Copyright (c) 2015年 张秀清. All rights ...