Когда вы помещаете функцию в другую функцию, скомпилированный код не создает ее один раз и повторно использует ее каждый раз.
Посмотрите на байт-код LuaJIT первого кода:
Это байт-код функции doSum
:
0001 GGET 0 0 ; "print"
0002 KSTR 1 1 ; "Give me a number"
0003 CALL 0 1 2
0004 GGET 0 2 ; "io"
0005 TGETS 0 0 3 ; "read"
0006 KSTR 1 4 ; "n"
0007 CALLT 0 2
Это начало функции readInputFromUser
:
0001 FNEW 0 0
0002 MOV 1 0
0003 CALL 1 2 1
...
...
...
Посмотрите на первую инструкцию:
0001 FNEW 0 0
FNEW
означает Create new closure from prototype D and store it in A
.
Эта инструкция создаст новое закрытие при каждом запуске readInputFromUser
(Закрытие - это функция внутри функции). Создание замыкания содержит несколько процедур. Он выделяет пространство для новой функции, добавляет в список G C, добавляет значения, локальные и многие другие вещи.
Это стоит времени ЦП, а также нарушает компиляцию JIT. (В простом Lua процессорное время для замыканий больше)
Ваша функция doSum
не использует никаких значений из readInputFromUser
, поэтому вместо этого вы можете создать doSum
снаружи readInputFromUser
и используйте его как значение upvalue (значение Upvalue является локальной переменной вне (и выше) функции). Upvalues стоит дороже, чем локальные, но создание замыкания стоит намного дороже, так что здесь можно использовать upvalue. Вы можете избежать этого повышения, сделав doSum
глобальным, но глобальные стоят немного больше (locals > upvalues > globals > closures
).
Сумма : Создание замыкания стоит дорого, если ваша функция не ' t использовать значения upval, вы можете создать его один раз снаружи и использовать повторно.
Кстати, у вас есть синтаксические ошибки в последнем print
и в doSum
определении. Кроме того, это приблизительный тест теста между первым кодом и вторым:
doSum inside readInputFromUser: 0.29265 (Min: 0.27215, Max: 0.35823, Average: 0.29573) second(s) (81816.93%) (818 times slower)
doSum as upvalue: 0.00036 (Min: 0.0003, Max: 0.00108, Average: 0.00042) second(s) (100%)