I’ve read up on coroutines for about a half hour, and I have a couple questions.
In the Unity docs for coroutines, it says “A coroutine is like a function that has the ability to pause execution and return control to Unity”. What exactly does it mean when it says “return control to Unity” ?
My understanding is that if I start a coroutine inside Update(), any code after the function call inside Update is not executed until the coroutine completes. (If that’s incorrect, please correct me.) That said, what happens to all the other Update() calls in other scripts. Are other Update() calls still executed despite a coroutine yielding in one Update() call ? What if I start a coroutine in Start(), then will the call to Update() in the same script be delayed?
I can’t find any details about what’s going on “under the hood”, and it’s confusing because they seem to act like threads with that “yield” keyword, but Unity does not support multithreading.
Don’t be afraid to get low-level because I really do want a strong understanding of what’s going on. I’ll be sure to upvote anything I find useful whether it be comments or answers.
EDIT: Here are 2 simple and straightforward resources that really helped me ( on top of the resources provided in the answers below ):
For 1. “Return control to Unity” means that whenever you call yield Unity is free to run code like normal. Update will finish, all of the other scripts will run. Rendering occurs and so forth. Once Unity detects that the yield period is over it resumes execution of the coroutine. This happens as part of the next Update cycle, rather then at an arbitrary point.
For 2. Your understanding is incorrect. If you call a coroutine the next line of code will begin executing immediately. All other Update functions carry on. Calling a coroutine does not delay code that called it. The only time a delay occurs is when you explicitly call yield inside a coroutine.
One way to think about coroutines is as simulated threads. They are not true threads, everything happens in the main thread. But they can pause execution and hand flow back to the calling function. Again worth noting the Unity resumes a coroutine during the update cycle (when Unity is expecting game updates to occur) rather then at an arbitrary point (as would happen with true multi threading).
Check out this very good video on coroutines. Its not beginner level, but if you have a solid understanding of C# it will help you understand how the simulated threading works under the hood.
By “return control to Unity” the documentation is referring to the fact that coroutines are non-blocking (when one is called within a piece of code using StartCoroutine(), the calling code doesn’t wait for the coroutine to finish before continuing).
My understanding is that if I start a coroutine inside Update(), any code after the function call inside Update is not executed until the coroutine completes.
This is incorrect because of the aforementioned “return control to Unity” behaviour. (The documentation should really say something like “return control to the function that called it”; just saying that control is returned to Unity as a whole is rather vague.) Any code after the coroutine call will be executed immediately after the coroutine is started (even if there is a delay in the coroutine itself).
If you’re interested in low-level details, this blog post (archived, as the site seems to be down at the moment) may be of interest.
“My understanding is that if I start a coroutine inside Update(), any code after the function call inside Update is not executed until the coroutine completes.”
It is true, You can easily check it.
Print something in update function after the startCoroutine like that;
void Update(){ if(sw){ StartCoroutine("func"); print("Hi!!!"); sw=false; } print("Hi2!!!"); } IEnumerator func(){ while(true){ print("Hi Coroutine"); yield return null; } }
you can see in the console:
Hi Coroutine,
Hi!!!,
Hi2!!!,
Hi2!!!,
Hi Coroutine,
Hi2!!!,
Hi Coroutine,
Hi2!!!,
…
So when a coroutine is started(StartCoroutine), first coroutine is executed and when it arrives to yield statement, it returns to the line after the startCoroutine in the update(for example).After that ,the coroutine is executed again when other functions have been finished