Bilal135 Posted January 15, 2020 Share Posted January 15, 2020 (edited) 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 January 15, 2020 by Bilal135 Link to comment
Scripting Moderators ds1-e Posted January 15, 2020 Scripting Moderators Share Posted January 15, 2020 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.) Link to comment
Simple0x47 Posted January 15, 2020 Share Posted January 15, 2020 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. 1 Link to comment
Scripting Moderators ds1-e Posted January 15, 2020 Scripting Moderators Share Posted January 15, 2020 (edited) 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 Separately: Edited January 15, 2020 by majqq 1 Link to comment
Bilal135 Posted January 15, 2020 Author Share Posted January 15, 2020 That sums it up. Thank you. Link to comment
Moderators IIYAMA Posted January 15, 2020 Moderators Share Posted January 15, 2020 (edited) 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 January 15, 2020 by IIYAMA 2 Link to comment
Moderators IIYAMA Posted January 15, 2020 Moderators Share Posted January 15, 2020 (edited) 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 January 15, 2020 by IIYAMA 1 Link to comment
Scripting Moderators ds1-e Posted January 15, 2020 Scripting Moderators Share Posted January 15, 2020 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 1 Link to comment
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now