Faster 'generic for' for raw table

18 views
Skip to first unread message

云风 Cloud Wu

unread,
7:51 AM (11 hours ago) 7:51 AM
to lu...@googlegroups.com
Lua 5.0 introduced generic for/pairs to replace Lua 4.0's direct
iteration of raw tables. While generic for is very powerful, there's a
small issue - it's somewhat slower because a function call is required
for each iteration.

I hope Lua can continue providing a direct way to iterate raw tables,
such as maintaining Lua 4.0's behavior when the first parameter of
generic for is 'nil' by iterating the second table object.

I wrote a small piece of code to conduct a comparative test between
Lua 5.5 and a minor patch I implemented in Lua 5.5 (Using lua_next
replaced ProtectNT(luaD_call(L, ra + 3, GETARG_C(i))); /* do the call
*/ in the case OP_TFORCALL)

local t = {}
for i = 1, 100000000 do
t[i] = i
end

local ti = os.clock()
for k in pairs(t) do
end
ti = os.clock() - ti
print(ti)

The original lua 5.5 cost 0.97s , and patched version (using lua_next
instead of luaD_call) cost 0.42s . It's almost twice as fast.
Considering that most scenarios involve iterating raw tables, I
believe this optimization is meaningful.

--
http://blog.codingnow.com

Spar

unread,
8:08 AM (11 hours ago) 8:08 AM
to lu...@googlegroups.com
As a reference, LuaJIT has some heuristics if for generator is called ipairs or pairs it will generate code better or faster code. It emits different bytecode
--
You received this message because you are subscribed to the Google Groups "lua-l" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lua-l+un...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/lua-l/CAJnYMr1V547AwTBnURckKDNbMmO85_L9WLZ28SiGK46kiUxfgQ%40mail.gmail.com.

Luiz Henrique de Figueiredo

unread,
8:29 AM (10 hours ago) 8:29 AM
to lu...@googlegroups.com
> The original lua 5.5 cost 0.97s , and patched version (using lua_next
> instead of luaD_call) cost 0.42s . It's almost twice as fast.

Add some real work in the loops like calling a function or
concatenating strings or creating tables and this difference will
probably decrease significantly.

云风 Cloud Wu

unread,
8:42 AM (10 hours ago) 8:42 AM
to lu...@googlegroups.com
Luiz Henrique de Figueiredo <l...@tecgraf.puc-rio.br> 于2026年6月12日周五 20:29写道:
True.

However, iterating tables is a fundamental operation, and considering
that tables are almost the only data structure in Lua, I believe even
a minor optimization would be valuable. In many cases, Lua's function
calls are still relatively slow. When optimizing performance hotspots,
we can use code generators to inline function calls into flat code.
However, iterating raw tables remains unavoidable. If the language
itself could provide a way to iterate raw tables, it would be very
useful

btw, there are also many cases where for loops do very little work.
Take penglight's tablex.lua as an example, most of the pairs-based
loops in that file contain almost just one or two lines of code.

https://github.com/lunarmodules/Penlight/blob/master/lua/pl/tablex.lua

--
http://blog.codingnow.com

云风 Cloud Wu

unread,
8:53 AM (10 hours ago) 8:53 AM
to lu...@googlegroups.com
云风 Cloud Wu <clo...@gmail.com> 于2026年6月12日周五 20:42写道:

> a minor optimization would be valuable. In many cases, Lua's function
> calls are still relatively slow. When optimizing performance hotspots,
> we can use code generators to inline function calls into flat code.
> However, iterating raw tables remains unavoidable. If the language
> itself could provide a way to iterate raw tables, it would be very
> useful

If we want to avoid calling pairs/next, storing the raw table's keys
in a sequence (like a list) can often double the speed. For example,
consider this code

local t = {}
for i = 1, 100000000 do
t[i] = i
end

local ti = os.clock()
local sum = 0
for k,v in pairs(t) do
sum = sum + v
end
ti = os.clock() - ti
print(ti, sum)

If we cache the keys into a sequence table first :

local keys = {}
local i = 1
for k in pairs(t) do
keys[i] = k
i = i + 1
end

And then use numerical for loop instead, It also has twice the performance.

local ti = os.clock()
local sum = 0
for i = 1, #keys do
sum = sum + t[keys[i]]
end
ti = os.clock() - ti
print(ti, sum)





--
http://blog.codingnow.com

Martin Eden

unread,
9:53 AM (9 hours ago) 9:53 AM
to lu...@googlegroups.com
My test (based on yours and lhf's recommendation) :

  -- Lua 5.5.0  Copyright (C) 1994-2025 Lua.org, PUC-Rio
  do
    local t = {}
    for i = 1, 100e6 do t[i] = i end

    local tic = os.clock()

    -- ( Test
    -- for i = 1, #t do t[i] = -t[i] end -- 1.41
    -- for i in ipairs(t) do t[i] = -t[i] end -- 2.60
    for i in pairs(t) do t[i] = -t[i] end -- 3.63
    -- )

    local tac = os.clock() - tic

    print(tac)
  end

No surprises for me, I'll still be using ipairs.

And hey, it's hundred millions operations under five seconds!
In my adolescence common-sense estimation was one million per second.

-- Martin

Reply all
Reply to author
Forward
0 new messages