Как вы предварительно настроить размер массива в Lua? - PullRequest
8 голосов
/ 24 сентября 2008

У меня есть программа 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?

В качестве альтернативы, есть ли другой способ избежать выделения памяти при добавлении объекта в таблицу?

Ответы [ 6 ]

9 голосов
/ 30 сентября 2008

Позвольте мне сосредоточиться на вашем вопросе:

добавление значений в ассоциативный массив по одному

Таблицы в Lua являются ассоциативными, но их использование в виде массива (1..N) оптимизировано. Они имеют двойные лица внутри.

Итак. Если вы действительно добавляете значения ассоциативно, следуйте приведенным выше правилам.

Если вы используете индексы 1..N, вы можете принудительно настроить одноразовый размер, установив t [100000] = что-то. Это должно работать до предела оптимизированного размера массива, указанного в источниках Lua (2 ^ 26 = 67108864). После этого все ассоциативно.

p.s. Старый метод 'setn' обрабатывал только часть массива, поэтому он не используется для ассоциативного использования (игнорируйте эти ответы).

p.p.s. Вы изучали общие советы по поддержанию высокой производительности Lua? то есть знать создание таблицы и, скорее, повторно использовать таблицу, чем создавать новую, использовать «local print = print» и т. д., чтобы избежать глобального доступа.

7 голосов
/ 29 сентября 2008
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.

5 голосов
/ 24 сентября 2008

Не думаю, что вы можете - это не массив, это ассоциативный массив, как хэш 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);

может быть то, что вам нужно.

Создает новую пустую таблицу и толкает это на стек. Новая таблица имеет пространство, предварительно выделенное для массива narr элементы и элементы без массива. Это предварительное распределение полезно, когда вы точно знать, сколько элементов стол будет иметь. В противном случае вы можете использовать функция lua_newtable.

2 голосов
/ 28 сентября 2009

Если вы объявите свою таблицу в коде с определенным количеством элементов, например:

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

, тогда Lua создаст таблицу с памятью, уже выделенной как минимум для n элементов.

Тем не менее, Lua использует метод 2-кратного выделения памяти, поэтому добавление элемента в таблицу редко приводит к перераспределению.

1 голос
/ 28 ноября 2008

Хотя это не отвечает на ваш главный вопрос, он отвечает на ваш второй вопрос:

В качестве альтернативы, есть ли другой способ избежать выделения памяти при добавлении объекта в таблицу?

Если вы запускаете Lua в пользовательском приложении, как я могу догадаться, начиная с написания кода на C, я предлагаю вам заменить распределитель на распределитель небольших значений Loki, это уменьшит мои выделения памяти в 100 раз. Это улучшило производительность за счет отказа от обращений к ядру и сделало меня гораздо более счастливым программистом:)

В любом случае, я попробовал другие распределители, но они были более общими и предоставили гарантии, которые не приносят пользы приложениям Lua (таким как безопасность потоков, размещение больших объектов и т. Д.), А также написание собственного распределителя небольших объектов может быть хорошей неделей программирования и отладки, чтобы получить правильное решение, и после поиска доступного решения распределитель Локи был самым простым и быстрым, что я нашел для этой проблемы.

1 голос
/ 24 сентября 2008

Есть еще внутренний luaL_setn, и вы можете скомпилировать Lua так, чтобы это выставлено как table.setn. Но похоже, что это не поможет потому что код, кажется, не делает никакого предварительного расширения.

(Также setn, как прокомментировано выше setn, относится к части массива таблицы Lua, и вы сказали, что вы используете таблицу в качестве ассоциативного массив)

Хорошая часть в том, что даже если вы добавляете элементы один за другим, Lua не увеличить массив таким образом. Вместо этого он использует более разумную стратегию. Ты все еще получить несколько выделений для большего массива, но производительность лучше, чем получая новое распределение каждый раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...