Bilal135

Faster way to iterate?

Recommended Posts

I have heard that inserting players in a new table with 'for i = 1, #playerTable' method reduces the time it takes for the loop to complete, as compared to the more common 'for k, v in ipairs / pairs' loop. I know that the first method is more efficient from Lua guides, but I fail to understand the logic behind it.

In the case of the common loop, it would directly iterate over the table returned by getElementsByType. As for the for i = 1 method, we would first have to add the contents of the table (returned by getElementsByType) in a new indexed table, in this instance, playerTable, and then we would loop over it once again to get the players in it.

I wrote the following code to compare the time it takes to finish each type of iteration. However, both results were 0. Perhaps, it is because the difference is so minute that the machine is not able to identify it? If that's so, whats the point of preferring the first type over the second, when the difference is barely noticeable?

local players = getElementsByType("player");
local playerTable = {};
local sT = getTickCount();

-- Supposed to be a faster way?
for i = 1, #players do
    playerTable[i] = players; -- Insert players in a new indexed table.
    outputChatBox(getPlayerName(playerTable[i][1]), root);
    local eT = getTickCount();
    outputChatBox(eT - sT, root); -- Output: 0
end

-- Compared to the more common loop
for k, v in ipairs(players) do
    outputChatBox(getPlayerName(v, root)); -- Directly access the contents of the table.
    local endTime = getTickCount();
    outputChatBox(endTime - sT, root); -- Output: 0
end

EDIT:

I realised there is no need to insert the players in a new indexed table. (Still the same output)

for i = 1, #players do
    outputChatBox(getPlayerName(players[i]), root);
    local eT = getTickCount();
    outputChatBox(eT - sT, root); -- Output: 1
end

-- Compared to the more common loop
for k, v in ipairs(players) do
    outputChatBox(getPlayerName(v, root)); -- Directly access the contents of the table.
    local endTime = getTickCount();
    outputChatBox(endTime - sT, root); -- Output: 1
end
  • Why is the first sort of iteration faster? 
  • Would the difference be even larger, if the number of players were extraordinarily large? If that's the case, I'd understand why we would want to use the first loop over the second.
Edited by Bilal135

Share this post


Link to post
1 hour ago, Bilal135 said:

I have heard that inserting players in a new table with 'for i = 1, #playerTable' method reduces the time it takes for the loop to complete, as compared to the more common 'for k, v in ipairs / pairs' loop. I know that the first method is more efficient from Lua guides, but I fail to understand the logic behind it.

In the case of the common loop, it would directly iterate over the table returned by getElementsByType. As for the for i = 1 method, we would first have to add the contents of the table (returned by getElementsByType) in a new indexed table, in this instance, playerTable, and then we would loop over it once again to get the players in it.

I wrote the following code to compare the time it takes to finish each type of iteration. However, both results were 0. Perhaps, it is because the difference is so minute that the machine is not able to identify it? If that's so, whats the point of preferring the first type over the second, when the difference is barely noticeable?


local players = getElementsByType("player");
local playerTable = {};
local sT = getTickCount();

-- Supposed to be a faster way?
for i = 1, #players do
    playerTable[i] = players; -- Insert players in a new indexed table.
    outputChatBox(getPlayerName(playerTable[i][1]), root);
    local eT = getTickCount();
    outputChatBox(eT - sT, root); -- Output: 0
end

-- Compared to the more common loop
for k, v in ipairs(players) do
    outputChatBox(getPlayerName(v, root)); -- Directly access the contents of the table.
    local endTime = getTickCount();
    outputChatBox(endTime - sT, root); -- Output: 0
end

EDIT:

I realised there is no need to insert the players in a new indexed table. (Still the same output)


for i = 1, #players do
    outputChatBox(getPlayerName(players[i]), root);
    local eT = getTickCount();
    outputChatBox(eT - sT, root); -- Output: 1
end

-- Compared to the more common loop
for k, v in ipairs(players) do
    outputChatBox(getPlayerName(v, root)); -- Directly access the contents of the table.
    local endTime = getTickCount();
    outputChatBox(endTime - sT, root); -- Output: 1
end
  • Why is the first sort of iteration faster? 
  • Would the difference be even larger, if the number of players were extraordinarily large? If that's the case, I'd understand why we would want to use the first loop over the second.

Related, perhaps you doing it wrong.

 

And yes for i = 1, #tablesize is faster, much people don't care much about performance. I can tell you that with integer loop, i achieved pretty nice performance boost on bone attach resource (and some other tricks.)

 

Share this post


Link to post
  • About why it is faster, pairs tries to get all the keys of one table (which means it doesn't look only for numbers as index). Meanwhile, making usage of a limited number of possible index values leaves you with faster results.
  • Try tables with at least 1000 values in order to see some difference.
  • Thanks 1

Share this post


Link to post
1 hour ago, Bilal135 said:

I have heard that inserting players in a new table with 'for i = 1, #playerTable' method reduces the time it takes for the loop to complete, as compared to the more common 'for k, v in ipairs / pairs' loop. I know that the first method is more efficient from Lua guides, but I fail to understand the logic behind it.

In the case of the common loop, it would directly iterate over the table returned by getElementsByType. As for the for i = 1 method, we would first have to add the contents of the table (returned by getElementsByType) in a new indexed table, in this instance, playerTable, and then we would loop over it once again to get the players in it.

I wrote the following code to compare the time it takes to finish each type of iteration. However, both results were 0. Perhaps, it is because the difference is so minute that the machine is not able to identify it? If that's so, whats the point of preferring the first type over the second, when the difference is barely noticeable?


local players = getElementsByType("player");
local playerTable = {};
local sT = getTickCount();

-- Supposed to be a faster way?
for i = 1, #players do
    playerTable[i] = players; -- Insert players in a new indexed table.
    outputChatBox(getPlayerName(playerTable[i][1]), root);
    local eT = getTickCount();
    outputChatBox(eT - sT, root); -- Output: 0
end

-- Compared to the more common loop
for k, v in ipairs(players) do
    outputChatBox(getPlayerName(v, root)); -- Directly access the contents of the table.
    local endTime = getTickCount();
    outputChatBox(endTime - sT, root); -- Output: 0
end

EDIT:

I realised there is no need to insert the players in a new indexed table. (Still the same output)


for i = 1, #players do
    outputChatBox(getPlayerName(players[i]), root);
    local eT = getTickCount();
    outputChatBox(eT - sT, root); -- Output: 1
end

-- Compared to the more common loop
for k, v in ipairs(players) do
    outputChatBox(getPlayerName(v, root)); -- Directly access the contents of the table.
    local endTime = getTickCount();
    outputChatBox(endTime - sT, root); -- Output: 1
end
  • Why is the first sort of iteration faster? 
  • Would the difference be even larger, if the number of players were extraordinarily large? If that's the case, I'd understand why we would want to use the first loop over the second.

It should be something like that: (if am i wrong i hope someone will correct me)

local startTick = getTickCount()
local players = getElementsByType("player")

-- ipairs

for i = 1, 10000 do
	for index, player in ipairs(players) do
		outputChatBox(getPlayerName(player))
	end
end

outputDebugString("ipairs done in "..getTickCount() - startTick.." ms.")

-- pairs

startTick = getTickCount()

for i = 1, 10000 do
	for index, player in pairs(players) do
		outputChatBox(getPlayerName(player))
	end
end

outputDebugString("pairs done in "..getTickCount() - startTick.." ms.")

-- int

startTick = getTickCount()

for i = 1, 10000 do
	for i = 1, #players do
		outputChatBox(getPlayerName(players[i]))
	end
end

outputDebugString("int done in "..getTickCount() - startTick.." ms.")

By the way, if you gonna use some variables in loop, it is better (faster) to declare them out of scope, and reuse them. I suggest to test it singly, because sometimes it could give you different results, as you can see here - pairs should be faster than ipairs - as far i know :D

DAXWo0O.png

Separately:

Kgp9Bd2.png

VJ8cm1T.png

67H48wE.png

 

Edited by majqq
  • Thanks 1

Share this post


Link to post

Just for the people that didn't notice it.

 

but ipairs as well as pairs are functions. Before you actually running the loop, you are executing (pre-process) functions.

 

players = {1,2,3,4}

theFunction, players2 = ipairs(players)

-- note: players and players2 are the same table (not a copy)

print(theFunction(players2, 0)) -- 1, 1
print(theFunction(players2, 1)) -- 2, 2
print(theFunction(players2, 2)) -- 3, 3
print(theFunction(players2, 3)) -- 4, 4

 

Edited by IIYAMA
  • Thanks 1

Share this post


Link to post
3 hours ago, majqq said:

By the way, if you gonna use some variables in loop, it is better (faster) to declare them out of scope, and reuse them. I suggest to test it singly, because sometimes it could give you different results, as you can see here - pairs should be faster than ipairs - as far i know

I do recommend for your tests to only use Lua function.

When using for example chat functions, MTA could/has have implemented a text buffer, if the queue is full it could either speed up or slow down the function speed (depending how it is programmed).

Edited by IIYAMA
  • Like 1

Share this post


Link to post
2 hours ago, IIYAMA said:

I do recommend for your tests to only use Lua function.

When using for example chat functions, MTA could/has have implemented a text buffer, if the queue is full it could either speed up or slow down the function speed (depending how it is programmed).

Thanks ☺️

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.