- Использовать более эффективные алгоритмы. Проверять эффективность бенчмарками, а не на глазок.
- Помнить, что компилятор Луа не делает никаких оптимизаций (кроме constant folding'а в некоторых случаях). В прикладном коде по возможности использовать LuaJIT / llvm-lua.
- Минимизировать число конкатенаций строк в несколько приёмов, особенно в циклах. Строки в Луа — константные, так что конкатенации в несколько приёмов засоряют память мёртвыми объектами. Заменять на table.concat() и, в прикладном коде, rope'ы. Множественные конкатенации в один приём (a = a .. b .. c) — дают одну инструкцию виртуальной машины, не страшно.
- Минимизировать число создаваемых таблиц. Каждый конструктор таблицы — аллокация.
- Минимизировать число создаваемых функций (замыканий) и корутин. Каждое такое создание — аллокация. Избегать необоснованного создания функций внутри функций и в циклах (однако это слишком полезный приём, чтобы от него отказываться полностью).
- Минимизировать число операций индексации таблиц, особенно hash-части таблицы. Помнить, что обращение к глобальной переменной — также индексация (глобального окружения), операторы "." и ":" — тоже индексация. По возможности кешировать результаты индексации в локальных переменных.
- Предпочитать хвостовую рекурсию. Вызов function() return foo() end эффективнее function() foo() end.
- Numeric for от 1 до размера таблицы дешевле pairs, pairs — дешевле ipairs.
- Выносить (там, где это осмысленно) создание объектов (таблиц, функций, корутин, юзердат) в глобальный chunk файла (но максимально ограничивать их область видимости).
- При использовании LuaJIT минимизировать число вызовов из Lua в C — маршаллинг в этом случае довольно дорогой. При использовании классического интерпретатора Lua маршаллинг практически бесплатный — наоборот может иметь смысл переписать на C наиболее медленные части кода.
25 июл. 2009 г.
Общие приёмы повышения производительности кода на Lua 5.1
Примерно в порядке убывания эффективности.
Подписаться на:
Комментарии к сообщению (Atom)
4 комментария:
7 - а в чём секрет?
9 - честно говоря не понял, можно подробнее?
7. Секрет в том, что return foo() -- tail call. При этом не создаётся запись в стеке вызовов.
9. Всё просто. Наивный пример:
-- Медленнее
local one_two_or_three = function()
local t = { 1, 2, 3 }
return t[math.random(#t)]
end
-- Быстрее
local one_two_or_three
do
local t = { 1, 2, 3 }
one_two_or_three = function()
return t[math.random(#t)]
end
end
спасибо
Отправить комментарий