- Home /
Calling StartCoroutine multiple times seems to stack
Hello there. I'm new to C# and I noticed that if you call StartCoroutine multiple times the Coroutine seems to stack. I just want to know if this is a expected behavior.
I managed to "solve" this by using StopCoroutine("MethodName") BEFORE StartCoroutine("MethodName").
In the example bellow if I use OneCall the Amount result is around 535, if I use TwoCalls the result is around 1035 .. and so on :
using UnityEngine;
using System.Collections;
public class CoroutineTest : MonoBehaviour {
// true means that the StartCoroutine will be called once.
public bool OneCall = true;
// true means that the StartCoroutine will be called twice.
public bool TwoCalls = false;
// Time in seconds that the test will be running.
public float TestTime = 10f;
// While looping times
public int Amount = 0;
void Start () {
// First call
StartCoroutine(Test ());
// Second call (activate it in the Unity Editor)
if(TwoCalls)StartCoroutine(Test ());
StartCoroutine (StopTest());
}
IEnumerator StopTest()
{
yield return new WaitForSeconds(TestTime);
OneCall = false;
}
IEnumerator Test()
{
Amount = 0;
while(OneCall){
++Amount;
yield return null;
}
}
}
Answer by aldonaletto · Aug 29, 2012 at 02:19 AM
Yes, coroutines run independently, like separate threads. When you start a coroutine, an instance of it is created and starts running. If you start the same coroutine again, another instance is created and runs independently of the other, and so on.
This is a blessing in some special cases, but much more often may become a curse: if you start a coroutine each Update, for example (a very common error), a new instance will be created each frame, crowding the memory and eating the CPU time in a few minutes. To avoid this, a solution is to use a boolean variable that's set when the coroutine starts and cleared upon finish, and check this variable before starting a the coroutine again - like this:
bool isRunning = false;
IEnumerator MyCoroutine(){
isRunning = true;
print("started");
yield return new WaitForSeconds(3);
print("3 seconds elapsed");
yield return new WaitForSeconds(3);
print("more 3 seconds");
yield return new WaitForSeconds(2);
print("ended");
isRunning = false;
}
void Update(){
if (!isRunning) StartCoroutine(MyCoroutine());
}
This code will call MyCoroutine repeatedly, but only one instance at a time due to the flag isRunning - if you don't check it, a new MyCoroutine will be created each frame. At 50 frames per second, for instance, you may have about 400 MyCoroutine instances running at the same time (each one lives for 8 seconds).
No coroutines are nothing like threads. They do not run independently but sequentially.
They work exactly like processes in a non-preemptive multitasking operating system (also known as cooperative multitasking).
The next coroutine in the queuing scheduler will not run until the current one yields.
Your answer is a little misleading.
Not quite. The main difference is that with preemptive multitasking there is no way to know when a context change will appear. With coroutines it appears at the yield instruction.
This can look like a small difference, but it has completely different consequences. And it requires some other approaches that are sometimes opposite.
I insist on this point to avoid misuse of recipes or solutions of problems regarding threads in the context of coroutines.
The rest of your answer is correct when you explain the creation of coroutine instances.
This boolean variable may become another problem if the coroutine is stopped manually or by deactivating the object. Then the variable will not be set to false because the coroutine will never finish. Should be used with caution.
Aldo, you could have left it at, It's a blessing, as, it is, considering Unity made it unattractive to use new Threads in Unity. The next 2/3s you hammer the point of obviously not starting Coroutines every frame, which the poster seems to know by the given example.
$$anonymous$$ryptos, of course in simple terms Coroutines are like threads for Unity, which is a plain blessing. The end user doesn't give two hoots about whether you implemented a new Thread or Coroutine in your awesome game, only that it works and the end result is the same. -- When I compare my Console app with a ticking Thread and an Input Thread with two Unity Coroutines that show similar output, the results are the same, therefore, learn some Earth language => Coroutines are LI$$anonymous$$E Threads. (That's a surface statement, which is 100% true!) You really don't need to be a Nazi about the irrelevant workings of each!!!