【问题标题】:Lua tables: performance hit for starting array indexing at 0?Lua 表:从 0 开始数组索引的性能下降?
【发布时间】:2014-12-04 13:11:16
【问题描述】:

我正在将 FFT 代码从 Java 移植到 Lua,我开始有点担心这样一个事实:在 Lua 中,表的数组部分从 1 开始索引,而在 Java 中,数组索引从 0 开始。

对于输入数组,这不会导致任何问题,因为 Java 代码已设置为处理所考虑的数据不在数组开头的可能性。但是,代码内部的所有工作数组都假定从 0 开始索引。我知道代码将按编写的方式工作——Lua 表就像那样棒极了——但我对性能影响完全没有意义我可能通过将数组的“0”元素放入底层 C 结构的哈希表部分(或者实际上,如果会发生这种情况)。

我的问题:这值得担心吗?我是否应该计划分析和手动优化代码? (该代码最终将用于转换许多事先不知道的长度不等的相对较小(> 100 个时间点)的信号。)

【问题讨论】:

  • 在分析显示您需要之后开始担心。我怀疑你不必担心。
  • 我对 Lua 文档的理解是没有真正的数组构造。表可以用作数组,但索引值实际上只是一个键。尽管我记得读过一些关于整数键存储在一个区域中并且字符串键存储在散列中的信息,但我不确定底层表示。您可以使用与“0”不同的零 (0) 整数键。见lua.org/pil/2.5.htmllua-users.org/wiki/TablesTutorial
  • 但是这个常见问题解答luafaq.org/gotchas.html#T6 说零 (0) 的整数索引将被放入表的散列部分。但是没有日期。本文档描述了 Lua 性能技巧,包括表的使用。 lua.org/gems/sample.pdf
  • 在 LuaJIT 中,0 处的元素将被放入表格的数组部分。
  • 底线,表格尽可能高效,因为(几乎)所有不是 Lua 中简单标量值的东西都是表格。 “数组部分”是一种优化,数组部分中的键不属于数组部分的键没有成本。

标签: lua lua-table


【解决方案1】:

我做了一些小的,可能不那么可靠的测试:

local arr = {}
for i=0,10000000 do
  arr[i] = i*2
end

for k, v in pairs(arr) do
  arr[k] = v*v
end

和以 1 作为第一个索引的类似版本。在我的系统上:

$ time lua example0.lua
real  2.003s

$ time lua example1.lua
real  2.014s

我也对 table.insert 的表现很感兴趣

for i=1,10000000 do
  table.insert(arr, 2*i)
...

而且,令人惊讶的是

$ time lua example2.lua
real 6.012s

结果: 当然,这取决于你运行的是什么系统,也可能是哪个 lua 版本,但似乎零启动和一启动之间几乎没有区别。更大的差异是由您将内容插入数组的方式造成的。

【讨论】:

  • table.insert 的循环由于全局查找、函数调用和每次arr 长度的计算,势必会变慢。但请注意,table.insert 的循环要长 10 倍...
  • 10 倍长的部分是一个错字:)。
【解决方案2】:

我认为这种情况下的正确答案是更改算法,以便所有内容都以 1 为索引。并考虑转换的那部分。

你的 FFT 不会让其他 Lua 用户(比如我)感到惊讶,因为所有“类似数组”的表都由一个索引。

考虑到 Lua 中数字循环的结构方式(其中“开始”和“结束”是“包含”),这可能不像您想象的那么紧张。你会交换这个:

for i=0,#array-1 do
  ... (do stuff with i)
end

通过这个:

for i=1,#array do
  ... (do stuff with i)
end

非数字循环将保持不变(如果您愿意,您也可以使用ipairs)。

【讨论】:

  • 这将涉及在 6,600 行代码中遍历所有 for-、while- 和 repeat-循环,并确定哪些索引需要更改,以及如何手动更改(许多循环索引用于设置其他索引的值和分配的值)。我决定使用这个端口的唯一原因是因为我可以通过算法完成大部分工作,只需要手工一点点工作;时间限制排除了更多涉及的内容,所以这个答案对我来说不是首发。
  • 我的意思是,当从 Java 翻译到 Lua 时,无论如何你都必须经历循环。
  • 不是手工我没有。我编写了代码来完成所有的翻译。
  • 那就更好了!您可以更改代码以一次性更改所有循环:)
  • 我们在这里得到的是......无法沟通。将 for 循环从 Java 转换为 Lua 是一对一的。在尝试修改循环的实际内容时保持正确性是不可行的。这基本上是一个相当简单的字符串替换和实际编写我自己的词法分析器和解析器以在整个代码库上运行之间的区别。
猜你喜欢
  • 2016-12-07
  • 2013-11-11
  • 1970-01-01
  • 2020-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-16
  • 1970-01-01
相关资源
最近更新 更多