Lots of great topics here on the dev forums if you just search
I have searched. But they don’t provide a definition of what they’re, rather a comparison between the two and other stuff. I just want to know, if anyone is willing to explain in depth.
they are both threads running at the same time with other events basically
Both Spawn()
and Coroutine
creates and runs a separate thread in the same script at the same time or some simplified version, you can run two different code blocks in the same script at the same time.
They are used for multi-threading and running 2 different codes in the same script at the same time so they are much like functions that runs when an event fires except you can chose when you want to run it.
Right now no use case comes into my mind and you wouldn’t need multi-threading in the same script for most of the time really.
What you should know about Coroutine
and Spawn()
is the information I gave you above and the fact that Spawn()
works just like Coroutine
except when you use Spawn()
it takes about 29 milliseconds to start running a separate thread because it has a hidden wait()
built in it where in Coroutine
it runs as soon as you tell the Coroutine
to run.
Also creating too many threads may cause slowdown and lag.
Very informative! thank you! :3
So basically they are used to run multiple threads. Interesting, I found this quite useful. What do you prefer using?
coroutines i use like 5 of them with loops or something and still get 60 fps
I prefer Coroutines over Spawn()
because it’s faster unless I want to run a function x seconds after I create a separate thread then I just use Delay()
instead which is the same thing as Spawn()
but you can choose how many seconds it will yield after the thread is created before running the function assigned to the thread.
Thanks for this information, however I have one last question. Considering that they both create a thread, do they require a call() to return the functions/information in it? the coroutine? so it can be called.
So, what kind of scenario would require to run blocks of code at the same time?
A block of code that depends on info from another block? Woildnt be easier just wait for the first response to continue with the other?
I have no knowledge about them, but since he said they can run at the same time. I was thinking perhaps things like a loop, which simultaneously runs lets say a random map chooser? Maybe I’m totally misunderstanding the use of it.
You can assign Coroutines to variables to run them later, unlike Delay() and Spawn() but (I should’ve mentioned this earlier) once you run the Coroutine and it finishes it’s job you can’t run it again without recreating and reassigning it.
As I said earlier, I don’t have any use that comes into my mind right now.
Sometimes, people will want multiple parts to change a certain property at the same exact time.
For example, if I wanted to change ten parts’ transparency all at the same time instead of waiting for each part to change its transparency like what a normal in pairs loop does, I would use a coroutine.
for i, v in pairs(parts:GetChildren) do
v.Transparency = 0.5
end
The above code will loop through each part and change their transparency one-by-one, whereas coroutines will make multiple parts change transparency to 0.5 all at the same time.
Ohh! I got it! Sounds very useful for specific tasks!
What about coroutines firing clients? FireAllClients() is a Loop? that goes one-by-one or its somekind of coroutine that “fires” all clientes at the same time?
Should I test coroutines vs firing all clients at the same time? its just a simple question about understanding the coroutines topic
That would still go through the parts one by one, as pairs
is iterating through the array one item at a time. A better example would be if you wanted two blocks of code to occur at nearly the same time, for example, with something I sometimes do, which’s to fade a UI background in and have the text scroll.
coroutine.resume(coroutine.create(function()
for FadeNum = 20, 0, -1 do
Bg.BackgroundTransparency = .6 + ((.4 / 20) * FadeNum)
wait(.1);
end
end));
for ScrollNum = 1, #Text do
TextLabel.Text = Text:sub(1, ScrollNum);
wait(.05);
end
Yeah, you have to call a coroutine; however, they all call differently from one another. For example, with wrap
local Foo = coroutine.wrap(function(Msg) -- Create a new coroutine
print(Msg); -- Output text given
end);
Foo("Hello World!"); -- Call the coroutine
As for create
/resume
local Foo = coroutine.create(function(Msg)
print(Msg);
end);
coroutine.resume(Foo, "Hello World!");
I prefer to use create
/resume
out of habit and years of use. But, while on this topic, I recommend checking out this
reply by evaera about spawn vs coroutine, as she does a great job explaining the downsides/disadvantages of using spawn
.
EDIT
I would recommend against using a coroutine where it isn’t necessary, it just bloats your code and can cause issues if not careful.
EDIT2
An afterthought, but I thought it would be good to note; coroutines can mask errors and skew them (coroutines also run under a protected all; the script wont break if/when it errors). By this, I mean you can get the error message, but sometimes it can be skewed - I don’t have an example for this (I can’t find a good example >.<).
Something also good to note’s that a coroutine can return values, but not for yielding methods/if the result’s yielded. However, the spawn
method does not take any arguments or return any values from a method.
local Bool, Value = coroutine.resume(coroutine.create(function()
-- wait(1); -- Uncommenting will have `Value` return a nil value
return 1;
end));
print(Bool, Value); -- "true 1" should print if a wait's not used
local Foo = coroutine.wrap(function()
-- wait(1);
return 1;
end);
local Bar = Foo();
print(Bar); -- "1"
Coroutines can be interesting, I recommend doing research on them. :>
It emulates multi-threading. Really what happens is that the code will go back and forth rapidly between the threads.
Coroutine is infamous for creating difficult errors to catch. And the spawn function is quite unoptimised. There are however alternatives that utilise bindable events.
There’s a trade off when using BindableEvent
s in place of coroutines. On the upside, it would return the error message without being skewed, but on the downside it’s fairly resource heavy.
If you’re constantly creating a “new coroutine” using bindable events, it’s going to create a new bindable event every time you were to create a “new coroutine”. To note, even if you destroy them after execution, it still takes a while for the garbage collector to come along and free up that space.
If anyone were to use this way of creating a “new coroutine”, I would only recommend it if you’re not intensively using it.
EDIT
My point wasn’t that using bindable events would replace coroutines, my point was that if you were to use them in place of a coroutine that the upsides and downsides should be taken note of, and that I didn’t recommend intensively using them in workflow.
No one said anything about replacing coroutines with bindable events, but indeed it is extremely expensive to use bindable events. But it shaves off the delay in spawn.
Coroutines die after they’re done running, so you can only coroutine.resume()
them once. After that, you have to recreate the coroutine.
You can stop this by using a loop and coroutine.yield()
:
local thread = coroutine.create(function()
while true do
print("hello")
coroutine.yield()
end
end)
coroutine.resume(thread) --> hello
print(coroutine.status(thread)) --> suspended
coroutine.resume(thread) --> hello
This way, the coroutine doesn’t die after you coroutine.resume()
it. Instead, it goes into a “suspended” state (that’s literally what it’s called) which makes it stop running until you coroutine.resume()
it again.
The while loop doesn’t make it run multiple times, it just stops it from dying after it runs once.