Оптимизация Lua сценариев

Оптимизация Lua сценариев

imring

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

Я покажу 6 примеров с оптимизацией, с которым я лично сам сталкивался при написании Lua скриптов. Для тестирования буду использовать Lua 5.1.5, Lua 5.4.2 и LuaJIT 2.1.0-beta3 (с функциями Lua 5.2). Lua 5.1 добавлена к сравнению потому, что LuaJIT базируется на этой версии.

Характеристика

Спасибо RoffDaniel за предоставленный сервер.

Локальные переменные

В языке существуют 2 типа переменных – глобальные и локальные. Глобальные хранятся в таблице _G (с Lua 5.2 существует еще _ENV), в свою очередь локальные – «в регистрах виртуальных машин». Многие люди, писавшие на языке Lua, рекомендуют избегать глобальные переменные, чтобы использовать локальные, так как «доступ к локальным значительно быстрее, нежели к глобальным».

Как видно, действительно доступ к локальным быстрее на Lua 5.1 на 20%, и Lua 5.4 на 30%, но LuaJIT показал одинаковый результат. Объяснение данного феномена на сайте JIT-компилятора я не нашел.

Заполнение таблицы

В Lua существует функция для записи значения в таблицу – table.insert. Но для записи в конец предпочитают использовать запись с помощью индексации, иначе говоря, a[#a + 1] или a[i].

a[i] оказался лучше всех по всем 3 результатам. a[#a + 1] показал хорошие результаты на «чистых» реализациях Lua.

Разбор таблицы

Если вам надо разобрать таблицу только с числовыми индексами 1.., то pairs не обязательно для этого использовать. Для этого случая существует функция ipairs. Некоторые используют традиционный способ – for i = 1, #a do. Я решил добавить еще реализацию с функцией table.maxn, но данной функции нету начиная с Lua 5.2 по причине того, что функция является устаревшей, и с next. Давайте взглянем на скорость.

#a оказалось лучше всех. Далее ipairs, который показал хорошие результаты в Lua 5.4 и в LuaJIT 2.1, но в Lua 5.1 почему-то показал результат хуже, чем pairs. Скорее всего, это погрешность. Хуже всех справилась реализация с next.

В LuaJIT table.maxn справилась лучше ipairs, нежели в Lua 5.1.

Конкатенация

Мне приходилось работать с большими текстами и я, как многие «скриптеры», использовал оператор .., но этот оператор работал медленно и я пытался найти альтернативу этому оператору. И мне удалось найти – функция table.concat.

Как видно по графикам, функция table.concat справилась намного лучше, чем оператор конкатенации строк.

string.char и string.byte

Когда я делал Xor test, то я задумался, а как можно еще быстрее ускорить, кроме вышеупомянутого table.concat. Я присмотрелся к функциям string.char и string.byte и решил заменить их на таблицы.

Таблица оказалась быстрее в Lua 5.1 и Lua 5.4, но для LuaJIT ничего не поменялось.

Вариативные аргументы

Видел много сценариев, где вариативные аргументы превращали в таблицу, потом использовали дальше. Этот вариант звучит неплохо, но мы в этой статье рассматриваем код, который будет быстрее работать. Поэтому вместо таблицы лучше использовать функцию select. Для теста добавил еще функцию table.pack (Lua 5.2+).

Функция select оказалась лучшим способом. Для JIT версии можно использовать table.pack, так как тоже быстро обрабатывает и на результате дает таблицу.

Выводы

В этой статье рассмотрено 6 способов для ускорения Lua сценариев, которые я встречал с 2017 года. Конечно, не все способы помогли для LuaJIT, но все же лучше использовать их и там.

Исходные коды Lua сценариев: https://github.com/FishLakeDev/speedtest/tree/main/lua-optimization

Результаты тестов в файле формата Microsoft Excel: https://t.me/fishlakedev_files/4

Подписывайтесь на мой канал в Telegram!

Report Page