Iteration of coroutines

What I’m really looking for is some way to simulate this:

IEnumerator Start(){
	for (int i = 0; i < endValue; i++){
		StartCoroutine(_Coroutine(i));
	}

	yield return [Wait until for loop has finished, before resuming];

	//Do more things
}

IEnumerator _Coroutine(int i){
	//Do things here with the only variable being i
}

At the moment, the only work around I can think of is:

	for (int i = 0; i < endValue; i++){
		yield return StartCoroutine(Coroutine(i));
	}

Obviously that’s not ideal as each iteration would wait for the previous one to complete, which (in my case) is unnecessary.

Could anyone shed some light on how to go about the problem? Cheers :smiley:

Edit to explain purpose:

I’m using the Google Play Unity plugin and have multiple leaderboards. I want to fetch the data from all the leaderboards, but prevent the user from playing until all scores are fetched. This is what I currently have:

IEnumerator GetHighscore(int i) {
	bool gettingScore = false;
	if (Social.localUser.authenticated) {
			gettingScore = true;

			PlayGamesPlatform.Instance.LoadScores(
				GPGSIds.leaderboard*,                 //Fetch scores from this leaderboard*
  •   			LeaderboardStart.PlayerCentered,        //Start from player position*
    
  •   			1,                                      //Get n results from position*
    
  •   			LeaderboardCollection.Social,           //Get the results from social/public*
    
  •   			LeaderboardTimeSpan.AllTime,            //No time length*
    
  •   			(data) => {*
    
  •   				//Callback*
    

_ Global.highscore2 = int.Parse(data.PlayerScore.formattedValue);_
* gettingScore = false;*
* }*
* );*

* }*
* yield return new WaitWhile(() => gettingScore);*
* }*

That’s a quite unusual case. Keep in mind that coroutines are cooperative routines which will execute one after another. Using coroutines here only makes sense if your “Coroutine” actually does something across multiple frames.

Starting say 100 of your Coroutines in one go means each of those coroutine will perform “one step” each frame. One step is everything from a yield to the next yield. So if you do heavy stuff inside the coroutines and you run a lot at the same time it will still cause performance issues. Coroutines can not be effectively used as load balancers. That’s not what they are for. They just allow several such routines to seemingly run in parallel but without any time control. It’s pure cooperative. If one routing doesn’t yield for 10 seconds your whole application will be freezed during that time.

Btw: It’s a bad idea to name your coroutine Coroutine as that’s the name of the Coroutine class in Unity. So you could get into name collision problems.

Anyways, if you want to start several coroutines at the same time and want to wait until all have finished you can store them into an array / list like this:

IEnumerator Start(){
    Coroutine[] coroutines = new Coroutine[endValue];
    for (int i = 0; i < endValue; i++){
        coroutines *= StartCoroutine(_Coroutine(i));*

}
for (int i = 0; i < endValue; i++)
{
yield return coroutines*;*
}
Debug.Log(“All coroutines have finished”);
}

IEnumerator _Coroutine(int i){
//Do things here with the only variable being i
}
Note that it’s important that you can only yield once on a Coroutine object. Never try to pass the same coroutine object two times to yield return, no matter if in the same coroutine or different ones. This will mess up the internal coroutine system and your coroutine can never finish and will wait infinitely. At least that’s how it used to be.
When you yield return a coroutine object of a coroutine that has already finished the yield will immediately return. This is pretty much the only case where a coroutine can be resumed multiple times per frame (ignoring special cases like waiting for fixedupdate or first yielding null and then WaitForEndOfFrame).
So when you start 100 coroutines and each will finish at a different frame, even when all except the first one have already finished, once the first one has finished your “controlling” coroutine will advance. Since each coroutine that has already finished will immediately return it will rush through the array until it hits a coroutine that hasn’t yet finished. At the time all coroutines have completed the second for loop will be done as well.
edit
As mentioned in my comment above, if you don’t mind to add some code to the coroutines you run, you can use an instance counter variable like this:
int instances = 0;
IEnumerator Start(){
instances = 0;
for (int i = 0; i < endValue; i++){
StartCoroutine(_Coroutine(i));
}
while (instances > 0)
yield return null;
}

IEnumerator _Coroutine(int i){
instances++;
//Do things here with the only variable being i
instances–;
}
Note: This is kind of dangerous. If a coroutine is terminated without executing the decrement at the end (due to an exception or StopCoroutine) your “Start” coroutine will be stuck as the variable will never return to 0.