This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Jummit's profile picture

Use the parallel api?

Started by Jummit, 18 March 2018 - 06:32 PM
Jummit #1
Posted 18 March 2018 - 07:32 PM
In my engine I have two functions; the draw and the update. I asked myself if I could use the parallel api like this to achieve better performance (because the game updates and looks that the delta time is right, and then the draw function waits a little longer, so there is always more delay) like this:

parallel.waitForAll(
  update(), -- takes 0.04 seconds to finish
  draw() -- takes less then 0.001 seconds to finish
) -- takes exactly the time of the update function when I test it
Will this be more efficient / faster then calling draw after update?
Edited on 18 March 2018 - 06:52 PM
Dog #2
Posted 18 March 2018 - 08:41 PM
I can't say whether that would be more efficient or faster, but keep in mind that the parallel API takes every function passed to it, turns it into a co-routine, then juggles those co-routines.

Having said that, in the code you provided you would be passing the results of update() and draw() to the parallel API, not actually handling the functions in parallel. You need to remove the brackets (parenthesis) from update() and draw() so that you are passing the actual functions to the parallel API.


parallel.waitForAll(update, draw)
Bomb Bloke #3
Posted 19 March 2018 - 01:48 AM
It's important to note that ComputerCraft only ever actively executes one coroutine at a time (world-wide!). That means that if "update" is executing, then "draw" isn't (and neither is any of the code on any of your other computers or turtles).

The change-overs occur whenever each coroutine yields, which typically happens when they attempt to pull events. So assuming "draw" never yields and you want to loop "draw" as many times as possible per "update" call, you could get pretty much the exact same effect by having "update" call "draw" just before every yield (the parallel API might be a neater way of doing that, but I'm just pointing out that the effect would be the same). If you want to loop "draw" once for every one "update" call, then you're instead only slowing things down this way (because you're building and managing co-routines that aren't benefiting you) and you should instead just run the functions one after the other. Obviously there's also no benefit if neither function yields.

I'm not sure how you're "measuring" the execution time of your functions. ComputerCraft itself can only measure time in 0.05 increments. 0.04s sounds remarkably slow to me, and if it's really that bad, then your Minecraft server wouldn't be able to handle many other computers without some noticeable slowdown.
Jummit #4
Posted 19 March 2018 - 09:19 AM
You need to remove the brackets (parenthesis) from update() and draw() so that you are passing the actual functions to the parallel API.
I actually did that in my code. I just messed that up in the example.

I'm not sure how you're "measuring" the execution time of your functions. ComputerCraft itself can only measure time in 0.05 increments. 0.04s sounds remarkably slow to me, and if it's really that bad, then your Minecraft server wouldn't be able to handle many other computers without some noticeable slowdown.
Its not the function that's so slow, I am just implementing a bit of delay, so the games are playable and don't rely on how many events you are firing.
Edited on 19 March 2018 - 08:19 AM
Bomb Bloke #5
Posted 21 March 2018 - 09:04 AM
Its not the function that's so slow, I am just implementing a bit of delay, so the games are playable and don't rely on how many events you are firing.

That sounds horribly like you're building a polling system on top of an event-based system. :S
Jummit #6
Posted 21 March 2018 - 09:19 AM
Its not the function that's so slow, I am just implementing a bit of delay, so the games are playable and don't rely on how many events you are firing.
Actually, the update function is slow because it is waiting for events. I don't use sleep or any other kind of delay code, I just update if enough time passed after the last update, if not then it cycles again.
Edited on 21 March 2018 - 08:22 AM
Bomb Bloke #7
Posted 21 March 2018 - 09:35 AM
That sounds odd. You can pull hundreds of events per second - it's not "slow". But if you're intentionally queuing and pulling garbage events over and over until os.clock() advances, then that'll slow down your whole server - it's a really bad practise.

If you want to know whether the clock's changed, just set a timer. If you want to tie "a lot" of things to certain times, then use a table to help tie those things to single timers.
Jummit #8
Posted 21 March 2018 - 10:00 AM
Just to clear things up a bit here, so we talk about the same thing; here is my update function:

local lastUpdate = os.clock()
function update(dt)
  event, var1, var2, var3 = os.pullEventRaw()
  if eventHandler[event] then
    eventHandler[event](var1, var2, var3)
  end
  if os.clock()-lastUpdate >=  dt then
    updateGame()
  end
end
and here is how it should be:

local updateTimer = os.startTimer(0.1)
function update(dt)
  event, var1, var2, var3 = os.pullEventRaw()
  if eventHandler[event] then
	eventHandler[event](var1, var2, var3)
  end
  if event == "timer" and var1 == updateTimer then
	updateGame()
	updateTimer = os.startTimer(0.1)
  end
end
Edited on 21 March 2018 - 09:01 AM
Bomb Bloke #9
Posted 22 March 2018 - 02:43 AM
Yes, that becomes more efficient, as it makes less calls on average. The original wasn't as bad as you were implying, though - it'll complete pretty much instantly if there's already an event in the queue.
Jummit #10
Posted 22 March 2018 - 08:03 AM
One problem the second option has is that dt has to be in 0.05 increments.
Edited on 22 March 2018 - 11:42 AM
Bomb Bloke #11
Posted 22 March 2018 - 08:42 AM
"Has to be" because…?

If you're thinking that you can't set a timer for 0.01s, that's not the case: it'll still fire a timer event, it just won't happen until the next server tick at the earliest. Given that os.clock() also won't increment until then, neither function has any advantage over the other as far as accuracy goes.