将表设置为空或将表的所有元素设置为n是否更好?

mas*_*tis 5 optimization lua

我最近在代码审查期间提出了一个关于一段lua代码的问题.有问题的代码是刷新缓存并使用一些数据重新初始化它:

for filename,_ in pairs(fileTable) do
    fileTable[filename] = nil
end

-- reinitialize here
Run Code Online (Sandbox Code Playgroud)

是否有任何理由不应该用这个替换上面的循环?

fileTable = { }

-- reinitialize here
Run Code Online (Sandbox Code Playgroud)

W.B*_*.B. 4

这是由于表调整大小/重新散列开销造成的。当表被创建时,它是空的。当您插入一个元素时,会发生重新散列,并且表大小会增长到 1。当您插入另一个元素时,也会发生同样的情况。规则是,只要没有足够的空间(在数组或散列部分)来容纳另一个元素,表就会增长。新的大小是可以容纳所需元素数量的最小 2 次方。例如,如果表包含 0、1、2、4、8 等元素,则在插入元素时会发生重新散列。

现在,您描述的技术可以保存这些重新哈希,因为 Lua 不会收缩表。因此,当您频繁进行填充/刷新表操作时,最好(性能方面)像您的示例中那样执行操作,而不是创建一个空表。

更新:

我做了一个小测试:

local function rehash1(el, loops)
    local table = {}
    for i = 1, loops do
        for j = 1, el do
            table[j] = j
        end
        for k in ipairs(table) do table[k] = nil end
    end
end

local function rehash2(el, loops)
    for i = 1, loops do
        local table = {}
        for j = 1, el do
            table[j] = j
        end
    end
end


local function test(elements, loops)
    local time = os.time();
    rehash1(elements, loops);
    local time1 = os.time();
    rehash2(elements, loops);
    local time2 = os.time();

    print("Time nils: ", tostring(time1 - time), "\n");
    print("Time empty: ", tostring(time2 - time1), "\n");

end
Run Code Online (Sandbox Code Playgroud)

结果很有趣。在 Lua 5.1 上运行,test(4, 10000000)nils 需要 7 秒,empty 需要 10 秒。对于大于 32 个元素的表,空版本速度更快(表越大,差异越大)。test(128, 400000)零点为 9 秒,空点为 5 秒。

现在在 LuaJIT 上,alloc 和 gc 操作相对较慢,test(1024, 1000000)nils 的运行时间为 3 秒,empties 的运行时间为 7 秒。

PS 请注意普通 Lua 和 LuaJIT 之间的纯粹性能差异。对于 1024 个元素表,普通 Lua 在大约 20 秒内完成了 100,000 次测试迭代,LuaJIT 在 10 秒内完成了 1,000,000 次迭代!