我们如何在Lua中预先调整数组大小?

时间:2020-03-06 14:38:02  来源:igfitidea点击:

我有一个Lua程序,它似乎比应该的要慢。我怀疑问题在于我一次将值添加到一个关联数组中,并且表每次必须分配新的内存。

似乎确实有一个table.setn函数,但是在Lua 5.1.3下失败了:

stdin:1: 'setn' is obsolete
stack traceback:
        [C]: in function 'setn'
        stdin:1: in main chunk
        [C]: ?

我从Google搜索中收集到的信息是,该功能在Lua 5.1中已弃用,但是我找不到什么(如果有的话)替代了该功能。

我们知道如何在Lua中对表格进行预大小设置吗?

另外,将对象添加到表时,还有其他方法可以避免分配内存吗?

解决方案

我不认为我们可以不是一个数组,而是一个关联数组,例如perl哈希或者awk数组。

http://www.lua.org/manual/5.1/manual.html#2.5.5

我认为我们不能从Lua方面有意义地预设其大小。

但是,如果要在C端分配数组,则

void lua_createtable (lua_State *L, int narr, int nrec);

可能就是我们所需要的。

Creates a new empty table and pushes
  it onto the stack. The new table has
  space pre-allocated for narr array
  elements and nrec non-array elements.
  This pre-allocation is useful when you
  know exactly how many elements the
  table will have. Otherwise you can use
  the function lua_newtable.

仍然有一个内部luaL_setn,我们可以编译Lua以便
它显示为table.setn。但这似乎无济于事
因为该代码似乎没有进行任何预扩展。

(此外,setn上面注释的setn与数组部分有关
Lua表的内容,我们说我们正在使用该表作为关联对象
大批)

好消息是,即使我们一一添加元素,Lua也不会
这样增加数组。相反,它使用更合理的策略。你还在
获得更大数组的多个分配,但性能优于
每次获得新的分配。

static int new_sized_table( lua_State *L )
{
    int asize = lua_tointeger( L, 1 );
    int hsize = lua_tointeger( L, 2 );
    lua_createtable( L, asize, hsize );
    return( 1 );
}

...

lua_pushcfunction( L, new_sized_table );
lua_setglobal( L, "sized_table" );

然后,在卢阿,

array = function(size) return sized_table(size,0) end

a = array(10)

为了快速运行此代码,我们可以将C添加到lua.c中。

让我更多地关注问题:

adding values to an associative array
  one at a time

Lua中的表是关联的,但是以数组形式(1..N)对其进行了优化。他们内部有两张脸。

因此,如果我们确实是在关联地添加值,请遵循上述规则。

如果使用索引1..N,则可以通过将t [100000] =设置为某值来强制一次调整大小。这应该一直起作用,直到在Lua源中指定的优化数组大小的限制为止(2 ^ 26 = 67108864)。之后,一切都是关联的。

p.s.旧的" setn"方法仅处理数组部分,因此对于关联用法没有用(忽略这些答案)。

p.p.s.我们是否研究了使Lua保持高性能的一般技巧?即知道表的创建,而不是重用一个表而不是创建一个新表,使用'local print = print'这样避免全局访问

尽管这不能回答主要问题,但可以回答第二个问题:

Alternatively, is there some other way to avoid memory allocation when you add an object to a table?

如果我们是在自定义应用程序中运行Lua(自从我们进行C编码以来就可以猜到),建议我们用Loki的小值分配器替换该分配器,这样可以减少100倍以上的内存分配。这样可以避免往返于内核,从而提高了性能,并使我成为一个更快乐的程序员:)

无论如何,我都尝试了其他分配器,但是它们更加通用,并且提供了不会使Lua应用程序受益的保证(例如线程安全性和大对象分配等),编写自己的小对象分配器也可以进行编程和调试的好星期,以使其正确无误,并在寻找可用的解决方案之后,Loki的分配器是我发现此问题最简单,最快的方法。

如果用代码声明表中包含特定数量的项,则如下所示:

local tab = { 0, 1, 2, 3, 4, 5, ... , n }

然后Lua将使用已为至少n个项目分配了内存的表来创建表。

但是,Lua使用2x增量内存分配技术,因此将项目添加到表中很少会强制重新分配。