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

[Tutorial] Parallel API

Started by Noodle, 08 June 2012 - 06:32 AM
Noodle #1
Posted 08 June 2012 - 08:32 AM
What is the Parallel API?
The parallel api allows you to run many functions at once. It checks for any functions listed in the line of code. It also allows sequencing.

Syntax
parallel.waitForAny(func1, func2, etc.)
parallel.waitForAll(func1, func2, etc.)

How these work
As you can see, waitForAny would wait for any to queue.
waitForAll is for sequencing, it waits for everything to complete.

Why is it helpful?
It helps because it doesn't require lots of lines of code to run 2 functions at one time. It was specifically made for multitasking.

How to use it properly
Say you have a function that you want it to receive all incoming messages.

function recv()
  while true do
	  id, msg = rednet.receive()
	  print(msg)
  end
end


Now you have another function that sends rednet.

function send()
  while true do
	  write("> ")
	  input = read()
	  rednet.broadcast(input)
  end
end

Now if you are lazy like 75% of all Americans (such obesity, it disgusts me.) You won't want to make a bunch of lines of code making it recv and send at the same time. This is what parallel prevents.

while true do
  parallel.waitForAny(recv, send)
end

It simply runs the functions simultaneously!
Pinkishu #2
Posted 08 June 2012 - 11:17 AM
Now if you are lazy like 75% of all Americans (such obesity, it disgusts me.)
*facepalm*

It simply runs the functions simultaneously!

Actually it runs them in turns till one of them finishes then the other is terminated (ofc that never happens cause of the while loops)
Noodle #3
Posted 08 June 2012 - 08:10 PM
@Pinkishu
xD (facepalm)
Saying, "It simply runs the functions simultaneously!" That was meant for people who are starters to lua.
kazagistar #4
Posted 08 June 2012 - 09:46 PM
Lying about abstractions is bad, because they always leak through.
Orwell #5
Posted 09 June 2012 - 04:29 AM
Now if you are lazy like 75% of all Americans (such obesity, it disgusts me.)
*facepalm*

It simply runs the functions simultaneously!

Actually it runs them in turns till one of them finishes then the other is terminated (ofc that never happens cause of the while loops)

But it doesn't run the two functions in turn, it alternates between the instructions inside. Right?
Noodle #6
Posted 09 June 2012 - 04:59 AM
@Orwell
No it doesn't alternate. Instead it runs the simultaneously (same time). <- Basic version
Pinkishu #7
Posted 09 June 2012 - 11:22 AM
Now if you are lazy like 75% of all Americans (such obesity, it disgusts me.)
*facepalm*

It simply runs the functions simultaneously!

Actually it runs them in turns till one of them finishes then the other is terminated (ofc that never happens cause of the while loops)

But it doesn't run the two functions in turn, it alternates between the instructions inside. Right?

Well it doesn't alternate between instructions.
It runs Function A, then if function A yields it runs Function B, then if Function B yields it runs Function A etc

"yielding" is done when the coroutine itself calls coroutine.yield() many functions seem to do so internally (e.g. pullEvent, sleep, etc)
matejdro #8
Posted 09 June 2012 - 01:10 PM
So, when one function yields, it will run second function until second one yields, then again first one and so on?

Thanks for explaining this , wiki documentation on this subject is IMHO very bad.
Pinkishu #9
Posted 09 June 2012 - 02:24 PM
Yeah it runes the first subroutine, then the second once the first yields and so on until its through all, then it restarts at the first
kazagistar #10
Posted 10 June 2012 - 03:15 AM
If one of the subroutines calls a yield that waits for a os message that does not come, or they are both waiting for an os message and steal it from the other, the abstraction starts breaking down very fast.
Cloudy #11
Posted 10 June 2012 - 08:53 AM
The way the parralel API works though, it won't "steal" the message from the other. Both coroutines will get the same message regardless of what the other does with it.

As for waiting for a message that does not come (I assume a os.pullEvent with an argument) I'm not sure but doesn't the parallel API keep sending events to the one which isn't listening for the specific event?
kazagistar #12
Posted 10 June 2012 - 09:07 PM
Right, nevermind, I don't know what I was thinking, I looked over the code again and it makes sense.
Noodle #13
Posted 11 June 2012 - 05:31 PM
@kazagistar
My code, incorrect? PFFT. Don't insult me.
(JK my code is sometimes incorrect, we all make mistakes)
kazagistar #14
Posted 11 June 2012 - 05:44 PM
I wasn't talking about your code, I was talking about the parallel API library.
Bossman201 #15
Posted 12 June 2012 - 12:26 AM
So does parallel only work one time unless you have a loop?
Noodle #16
Posted 13 June 2012 - 05:21 AM
@Bossman201
Yes.
Darky_Alan #17
Posted 24 July 2012 - 09:28 AM
Wouldn't this just jump between functions till one of them does something? Don't really feel the simultanious vibe, more of a jumping loops.

"Oh hey have you heard your signal yet?"

"No, it's your turn to listen for yours, I'll take an extremely short break."

And vice versa?
Noodle #18
Posted 24 July 2012 - 09:30 AM
Nope, simultaneous. Keeps them both alive.
– I think it just does it so fast that it won't exit or its using sockets.
Darky_Alan #19
Posted 24 July 2012 - 09:31 AM
– I think it just does it so fast that it won't exit or its using sockets.

Kinda what I meant by "an extremely short break".

What are sockets?
Noodle #20
Posted 24 July 2012 - 09:34 AM
^ What I meant is that its so short that it will keep receiving with no lag 0.0
Read wiki on sockets… Kinda hard to explain; Wiki
Its similar to that, that is more networking.
Darky_Alan #21
Posted 24 July 2012 - 09:37 AM
^ What I meant is that its so short that it will keep receiving with no lag 0.0
Read wiki on sockets… Kinda hard to explain; Wiki
Its similar to that, that is more networking.

I haven't even bothered working with rednet yet, I'll poke around with it later. I'll bookmark the link for now, thanks.
Noodle #22
Posted 24 July 2012 - 09:41 AM
Well its not only used for that, Its more just and explanation of what a socket is
Like pistons
Say you have 2 pistons
Both are 2 different functions.
You can only power one at a time from 1 side.
0
0 ——-+
——————— OR
0 ——-+
0

Using this api it opens the other side so they can both be powered at the same time.
+ ——– 0
0 ——– +
jamiemac262 #23
Posted 16 August 2013 - 03:59 PM
okay so what this sounds like to me is parallel doesnt mean paralell, it mean one then the other

so how do i make this work

it's supposed to run an alarm using immibis peripheral speaker until user enters password

function alarm()
p = peripheral.wrap("speaker_1")
p.start(1, 500)
sleep(1)
p.stop(1)
p.start(1, 400)
sleep(1)
p.stop(1)
alarm()
end

function relog()
term.clear()
term.setCursorPos(1,1)
print "Enter Your Password"
pass = io.read()
if pass == "password" then
return

else
term.clear()
print "ERROR:X101:: Incorrect Password"
print "Press [ENTER] to continue"
io.read()
relog()
end
end

parallel.waitForAny(relog(), alarm())
p.stop(1)
shell.exit()
svdragster #24
Posted 16 August 2013 - 04:28 PM
okay so what this sounds like to me is parallel doesnt mean paralell, it mean one then the other

so how do i make this work

it's supposed to run an alarm using immibis peripheral speaker until user enters password

I think you have to remove the brackets
parallel.waitForAny(relog(), alarm())
parallel.waitForAny(relog, alarm)
DarkEspeon #25
Posted 19 August 2013 - 09:14 PM
Actually, what parrallel does, is what i believe to be like what a computer does, it alternates between the two extremely quickly, like it gives computations to one for mere milliseconds, then switches and gives the next milliseconds, ect. , with wait for any until one returns, and with waitforall it waits for all to return
theoriginalbit #26
Posted 19 August 2013 - 10:25 PM
Actually, what parrallel does, is what i believe to be like what a computer does, it alternates between the two extremely quickly, like it gives computations to one for mere milliseconds, then switches and gives the next milliseconds, ect. , with wait for any until one returns, and with waitforall it waits for all to return
Kinda. What coroutines do in Lua is slightly different than what the computer does (in a multiprocessor machine). With coroutines, no matter the system only one will run at a time and the next will not run until the current one has yielded. This is why in CCLua we have the "too long without yielding error". This differs from the (multiprocessor) computers running threads as they are actually able to run multiple threads concurrently.
The main point to take from what I said here is that the coroutine must yield, control is not revoked every millisecond, the routine must yield its control.
immibis #27
Posted 15 September 2013 - 07:20 PM
The last loop is unnecessary, since send and recv never return.
JuanDaniel2510 #28
Posted 30 October 2013 - 07:03 AM
How can I do to send arguments without using global variables in parallel functions?

I know I can't do this parallel.waitForAny( func1(arg1,arg2,…), func2(arg1,arg2,…),…)
Wojbie #29
Posted 30 October 2013 - 07:07 AM
How can I do to send arguments without using global variables in parallel functions?

I know I can't do this parallel.waitForAny( funt1(arg1,arg2,…), funt2(arg1,arg2,…),…)

you can cheat a little and do this

parallel.waitForAny(
 function()
  funt1(arg1,arg2,...)
 end
,
 function()
  funt2(arg1,arg2,...)
 end
,...
)
Kingdaro #30
Posted 11 November 2013 - 08:58 AM
There's another way; you can have your function return another function to actually be used as a parallel. Note that it's usually only best used when you want to use a single function many times, but with different arguments.


function foo(msg, num)
	return function()
		for i=1, num do
			print(msg)
			sleep(math.random() * 2 + 1)
		end
	end
end

parallel.waitForAll(
	foo("hello", 10), --# returns a function that will print "hello" 10 times
	foo("world", 20)  --# returns a function that will print "world" 20 times
)
Edited on 11 November 2013 - 07:58 AM
Cozzimoto #31
Posted 15 November 2013 - 05:43 PM
@Noodle
i noticed in your OP you have the while loops within the functions your going to run in parallel. My question is wouldnt you want the while loop to run the parallel like so


local func1 = function()
  -- CODE HERE
end
local func2 = function()
  -- MORE CODE
end

while true do
  parallel.waitForAny( func1, func2 )

end

If there is a difference what would your advantages/disadvantages be?
Wojbie #32
Posted 15 November 2013 - 06:57 PM
waitForAny ends when any one of functions ends - all other get terminated. so if func1 ends then func2 if forcefully ended. This can cause weird/unpredictable. situations. bye using while true end loops inside functions you ensure they never end - so there will never be said situation.
At same time this can be what you need in your program soo….

Using waitForAll has this difference from Any that it waits for all to end - so if func1 ended it will wait for func2. This is again different situation - and that means you can never bee sure that both are run "at same" time.

So basically using any and while true end loops is usually exactly what you need from 3 hypothetical situations i presented here.
Cozzimoto #33
Posted 15 November 2013 - 07:24 PM
Thanks for the clarification Wojbie, i appreciate it +1
distantcam #34
Posted 15 November 2013 - 09:32 PM
waitForAny ends when any one of functions ends - all other get terminated.

I'm not so sure about that second bit. waitForAny does return after one of the functions ends, but I think the other functions are suspended and can be resumed, rather than terminated.
theoriginalbit #35
Posted 15 November 2013 - 11:03 PM
I'm not so sure about that second bit. waitForAny does return after one of the functions ends, but I think the other functions are suspended and can be resumed, rather than terminated.
If you have references to the coroutines then yes you could resume it, but the way that most people use parallel.waitForAny means that once one function is completed the others will become suspended, and eventually killed and cleaned up by the Java Garbage Collector…
Wojbie #36
Posted 16 November 2013 - 05:55 AM
If you have references to the coroutines then yes you could resume it, but the way that most people use parallel.waitForAny means that once one function is completed the others will become suspended, and eventually killed and cleaned up by the Java Garbage Collector…
Worth to point out is that standard parallel don't give you access to those references so there is no way that i know for them to get resumed. So they will get cleaned up by Garbage Collector.