在Lua中将函数嵌套在另一个函数中是否会提高性能?

如果我将一个函数放入另一个函数中,在我们添加到函数中的函数中调用它,例如以下示例:

local function readInputFromUser()
    local doSum()
        print("给我一个数字")
        return io.read("n")
    end
    num1 = doSum()
    num2 = doSum()
    print("" num1 .. "和" .. num2 "的总和" num1 + num2)
end

与像以下示例中启动的函数调用相比,它会为程序提供性能提升吗?

local doSum()
    print("给我一个数字")
    return io.read("n")
end

local function readInputFromUser()
    num1 = doSum()
    num2 = doSum()
    print("" num1 .. "和" .. num2 "的总和" num1 + num2)
end

对于性能,将doSum()函数放在第二个示例中作为全局函数也有好处吗?

点赞
用户8621712
用户8621712

当你将一个函数放在另一个函数内部时,编译后的代码不会将其创建一次并在每次重复使用。

看一下第一段代码的LuaJIT字节码:

这是“doSum”函数的字节码:

0001    GGET     0   0      ; "print"
0002    KSTR     1   1      ; "Give me a number"
0003    CALL     0   1   2
0004    GGET     0   2      ; "io"
0005    TGETS    0   0   3  ; "read"
0006    KSTR     1   4      ; "n"
0007    CALLT    0   2

这是“readInputFromUser”函数的开始:

0001    FNEW     0   0
0002    MOV      1   0
0003    CALL     1   2   1
...
...
...

看一下第一个指令:

0001 FNEW 0 0

FNEW代表“从原型D创建新闭包并将其存储在A中”。

每次运行readInputFromUser,此指令将创建一个新的闭包(闭包是函数内部的函数)。 创建闭包包含多个过程。它会为新函数分配空间,添加到GC列表中,添加upvalue,locals和其他诸多东西。

这需要CPU时间,也会打破JIT编译。(在普通的Lua中,闭包的CPU时间更长)

您的函数“doSum”没有使用来自“readInputFromUser”的任何值,因此可以在“readInputFromUser”之外创建“doSum”并将其用作upvalue(upvalue是函数外部(和上方)的局部变量)。 upvalue的成本更高,但闭包的创建成本比upvalue高得多,因此在此处使用upvalue是可以的。 您可以通过将“doSum”设置为全局变量来避免使用upvalue,但全局变量的成本稍高( locals > upvalues > globals > closures)。

总结:创建闭包很昂贵,如果函数不使用upvalue,则可以在外部创建它并重复使用。

顺便说一下,最后一个“print”和“doSum”定义中有语法错误。 此外,这是第一段代码和第二段代码之间的大致基准测试:

doSum在readInputFromUser内部:0.29265秒(最小值:0.27215秒,最大值:0.35823秒,平均值:0.29573秒)(81816.93%)(慢818倍)
doSum作为upvalue:0.00036秒(最小值:0.0003秒,最大值:0.00108秒,平均值:0.00042秒)(100%)
2020-03-25 15:45:56