微优化:从函数末尾的内部块返回
Micro optimization: Returning from an inner block at the end of a function
在 javascript 或(也许?)lua 等语言中,默认情况下所有函数都被视为在末尾有一个 return
语句:
function() {
// do
return;
}
等于
function() {
// do
}
我想知道从函数末尾的内部块返回是否会改变核心、编译过程、VM 中的任何内容。
function() {
if (condition) {
return;
}
// end of function
}
同样的问题适用于打破循环:
function() {
for ( loop ) {
return;
}
// end of function
}
当循环中断或条件检查结束时,机器 "look" 会做任何事情吗?
这不是文体问题,请不要告诉我要使代码可读。
TL:DR / 优化建议:您无需执行任何特殊操作即可获得性能。 if(condition) return
内部循环通常至少与到达函数末尾的 if(condition)break;
一样有效。
将嵌套循环放入函数内,这样您就可以将 return
用作多级 break
,这是无需 goto
即可有效表达逻辑的好方法,对人类来说很容易,对 compilers/interpreters.
来说也很容易
使循环条件更复杂以避免在一个函数中使用多个 return
语句对性能没有帮助。
通常不会,函数中间的 return
与在末尾到达隐式 return 没有根本的不同或效率更高或更低。 函数 底部 的显式 return 也不是特殊的。
(我假设我们谈论的是从不 return 值的 void 函数。显然 return 值与不 return 值不同。)
将代码重构为 break
循环并到达函数底部的隐式 return
并不是更有效(但很容易 less 在一些解释性语言中很有效,尤其是当它们不是 JIT 时。)例如如果解释器在函数内进行了一次跳转,然后必须进行另一次跳转。 (一个好的提前编译器或 JIT 优化器可以看到正在发生的事情并生成好的机器代码。)
一些编译器/解释器可能会通过跳转到所有 return
语句共享的公共清理块(结语)来处理 return
。 但尾部复制是可能的:当编译为机器代码时,一个函数可以有多个尾部副本 + ret
指令,可从不同路径访问。
(JavaScript 实现 do 通常将 JIT 函数转换为机器代码;IDK 大约 LUA。当然它们可以内联函数。return
内联函数中的语句可以只是简单的跳转,也可以完全优化掉。)
我不确定我是否正确理解了你的问题,但我会尝试从我的角度来回答。
函数声明末尾的return
语句表示离开函数,return什么都不做(void)。如果省略 return
语句,则在实际函数执行后不会发生任何事情。因此,我认为您声明的两个函数的行为方式不同:
function a() {
// executes until the following statement and then breaks
return;
}
function b() {
// executes all statements and afterwards leaves the context where it was called
}
关于你关于条件检查或循环等内部块的问题,我猜这些语句只能由解析器以某种方式 "optimized" 如果它们由数字或字符串等静态值组成。一旦出现任何像变量这样的动态值,就不可能优化任何东西或从内部 result
语句中获得优势。
希望你能明白我的解释。
在 javascript 或(也许?)lua 等语言中,默认情况下所有函数都被视为在末尾有一个 return
语句:
function() {
// do
return;
}
等于
function() {
// do
}
我想知道从函数末尾的内部块返回是否会改变核心、编译过程、VM 中的任何内容。
function() {
if (condition) {
return;
}
// end of function
}
同样的问题适用于打破循环:
function() {
for ( loop ) {
return;
}
// end of function
}
当循环中断或条件检查结束时,机器 "look" 会做任何事情吗?
这不是文体问题,请不要告诉我要使代码可读。
TL:DR / 优化建议:您无需执行任何特殊操作即可获得性能。 if(condition) return
内部循环通常至少与到达函数末尾的 if(condition)break;
一样有效。
将嵌套循环放入函数内,这样您就可以将 return
用作多级 break
,这是无需 goto
即可有效表达逻辑的好方法,对人类来说很容易,对 compilers/interpreters.
使循环条件更复杂以避免在一个函数中使用多个 return
语句对性能没有帮助。
通常不会,函数中间的 return
与在末尾到达隐式 return 没有根本的不同或效率更高或更低。 函数 底部 的显式 return 也不是特殊的。
(我假设我们谈论的是从不 return 值的 void 函数。显然 return 值与不 return 值不同。)
将代码重构为 break
循环并到达函数底部的隐式 return
并不是更有效(但很容易 less 在一些解释性语言中很有效,尤其是当它们不是 JIT 时。)例如如果解释器在函数内进行了一次跳转,然后必须进行另一次跳转。 (一个好的提前编译器或 JIT 优化器可以看到正在发生的事情并生成好的机器代码。)
一些编译器/解释器可能会通过跳转到所有 return
语句共享的公共清理块(结语)来处理 return
。 但尾部复制是可能的:当编译为机器代码时,一个函数可以有多个尾部副本 + ret
指令,可从不同路径访问。
(JavaScript 实现 do 通常将 JIT 函数转换为机器代码;IDK 大约 LUA。当然它们可以内联函数。return
内联函数中的语句可以只是简单的跳转,也可以完全优化掉。)
我不确定我是否正确理解了你的问题,但我会尝试从我的角度来回答。
函数声明末尾的return
语句表示离开函数,return什么都不做(void)。如果省略 return
语句,则在实际函数执行后不会发生任何事情。因此,我认为您声明的两个函数的行为方式不同:
function a() {
// executes until the following statement and then breaks
return;
}
function b() {
// executes all statements and afterwards leaves the context where it was called
}
关于你关于条件检查或循环等内部块的问题,我猜这些语句只能由解析器以某种方式 "optimized" 如果它们由数字或字符串等静态值组成。一旦出现任何像变量这样的动态值,就不可能优化任何东西或从内部 result
语句中获得优势。
希望你能明白我的解释。