【问题标题】:Optimising Lua code through using local functions通过使用本地函数优化 Lua 代码
【发布时间】:2020-04-17 15:43:27
【问题描述】:

所以,我知道将全局函数分配给局部变量会使它们运行得更快,就像编写代码一样:

local _cos = math.cos
for i = 1, 100000 do
    _cos(i)
end

比没有首先本地化函数的代码快得多:

for i = 1, 100000 do
    math.cos(i)
end

但是,根据我的测试,tonumbertypepairs 之类的东西似乎不起作用。

有人能解释一下为什么一些全局函数变得更快,而另一些似乎根本没有受到影响吗?

【问题讨论】:

  • 我知道的唯一区别是获取tonumber 需要一个表访问权限(_ENV.tonumber),而获取cos 需要两个表访问权限(_ENV.math.cos)。本地化 tonumber 真的一点都没有加快速度吗?
  • 如您所说,这可能与表访问次数有关。是的,在本地化 tonumber 时速度并没有提高,这也让我感到惊讶。

标签: lua


【解决方案1】:

本地化全局函数并不会让它们明显更快。它使它们有点更快,因为您不必在_ENV 中查找它们;特别是如果他们在另一个表中,例如_ENV.math.cos。对于直接在_ENV 中的函数,这种影响显然更小,如果函数本身运行速度很慢,本地化的微小差异就不会那么明显。

事实上,你不应该仅仅因为本地化函数。如果您有一个非常小的循环体,其中有很多迭代调用了一个非常小的函数,那么您应该考虑对其进行本地化(并且您应该尽可能靠近循环执行此操作),但前提是您确定这将使差异(基准测试是您的朋友)。

似乎一直存在这样的神话,即仅将您要使用的每个函数本地化到整个库就会神奇地使其更快,这完全是一种误解。

LuaJIT 甚至在大多数情况下自己都会这样做;检测循环体内重复的表访问并将其本地化到循环外。

另外请记住,虽然math.cos 永远不应更改,但您可能正在访问其他模块中的函数,该函数实际上会在后台更改以反映模块中的某些状态更改。在这种情况下,本地化函数将意味着您正在使用过时的函数。这不是很常见,但确实会发生。


只是为了好玩;尝试在 PUC Lua 和 LuaJIT 中运行它:

local function bench(n, fn, ...)
    local t1 = os.clock()
    for i=1,n do
        fn(...)
    end
    local t2 = os.clock()
    return t2 - t1
end

local n = 1e7

print(bench(n, function() return math.cos(20) end))
print(bench(n, function() return tostring(20) end))
print(bench(n, function() return tonumber("20") end))
print("---------")
print(bench(n, math.cos, 20))
print(bench(n, tostring, 20))
print(bench(n, tonumber, "20"))

【讨论】:

  • 我认为 +30% 是显着的性能提升。例如,我的测试以及 Roberto Ierusalimschy 的 Lua 性能提示(请参阅:lua.org/gems/sample.pdf)显示,使用数学表中的函数可以显着提高性能。但是,您对为什么直接位于 _ENV 中的条目可能不正确的解释是有道理的。
  • 尽管如此,你不会得到 +30% 的提升;如果您的函数执行连接数据库之类的操作,则函数本地化等小细节将完全丢失。正如我所说,基准测试确实是决定本地化内容的最佳方法,但只是无缘无故地进行会使代码变得不必要地复杂化。
  • @DarkWiiPlayer - doing it for no reason needlessly complicates the code - 你能在你的代码中对local clock = os.clock 说同样的话吗? ;-)
  • 可以说,n = 1e7,是的,这有点无关紧要;但为了保持该代码通用,我试图避免在循环结束后立即进行双表查找,以使t2 尽可能接近基准测试的实际结束。
  • 另外请注意,我在函数内部本地化了clock,所以我不会将引用保存的时间超过我的代码执行时间;所以基本上每次我将控制流返回给调用代码时,我都会“使我的缓存无效”,以防os.clock在其他地方发生变化;D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-04-22
  • 2011-11-22
  • 1970-01-01
  • 1970-01-01
  • 2019-12-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多