I never heard of anything like that. The documentation on coroutines does not mention any of that either. And it also sounds like one of those "If you have to ask, you are doing things wrong" limits to me.
But to prove it, I made a little test setup.
using System.Collections;
using UnityEngine;
public class MassCoroutineTest : MonoBehaviour
{
private int counter;
void Update()
{
Debug.Log($"{counter} coroutines reporting in!");
counter = 0;
if (Input.GetKeyDown(KeyCode.Space)) {
for (var i = 0; i < 10000; i++) {
StartCoroutine(TestRoutine());
}
}
}
IEnumerator TestRoutine() {
while(true) {
counter++;
yield return null;
}
}
}
This script generates 10,000 new coroutines whenever you press space. It counts how many of those coroutines actually got executed this frame and outputs the number. I drove this to a million coroutines without the counter ever turning out an uneven number. And then I quit because I only had 1.5 FPS anymore and it got annoyingly unresponsive.
So no, it's a myth. When there is indeed a hard limit on coroutines, you are not going to hit it while still having an acceptable framerate.
But I can imagine how such a myth is created. Game architectures based on lots and lots of coroutines can get really difficult to navigate and debug. You have spooky actions at a distance everywhere and you have no idea how many coroutines are active on which game object and what they are doing. So a codebase that uses a lot of coroutines often becomes really buggy and hard to troubleshoot. But it's always easier to blame the tools you are using than it is to blame yourself for not using them properly. So instead of admitting to themself that they screwed their architecture through over-reliance on coroutines and don't understand it anymore, people go around the Internet and tell everyone it has to be Unity and its coroutine management itself that is buggy.
By the way, I usually use coroutines in my code very rarely. When I want to wait until something happens, then I put the check for that condition into the Update()
method of an appropriate component. When I want things to happen in a sequence, then I usually program a simple state machine.
Update: João Mendes in the comments wonders if there might be a limit on nested coroutines. Well, I tried that too by using a recursive coroutine that starts itself:
IEnumerator RecursiveRoutine() {
counter++;
yield return StartCoroutine(RecursiveRoutine());
}
This code actually causes a StackOverflowException
at a depth of 272 coroutines. But that's a visible error in the console, not just a silent fail. When your game doesn't work and there are exceptions in the console caused by your own code, then that's on you, not on Unity! And it's to be expected that this error happens, because StartCoroutine
immediately starts the execution of the coroutine method until the first yield
.
However, when you yield for a frame before creating the coroutine, then you no longer have that problem:
IEnumerator RecursiveRoutine() {
counter++;
yield return null;
yield return StartCoroutine(RecursiveRoutine());
}
it seems to run just fine. There is not even an FPS drop. Well, it runs fine, but interestingly the Unity editor crashes occasionally when you let this run for a while and then exit play mode. So recursively calling coroutines might not be such a good idea after all.