Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Phur3ouZ · Sep 13, 2016 at 12:30 PM · coroutineloop

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 :D


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[i],                 //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[i] = int.Parse(data.PlayerScore.formattedValue);
                     gettingScore = false;
                 }
             );
         
     }

     yield return new WaitWhile(() => gettingScore);
 }
Comment
Add comment · Show 4
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image doublemax · Sep 13, 2016 at 12:38 PM 1
Share

I don't know if it's a solution or a workaround, but here's what i'd do:

Before starting the coroutines, init a counter with 0.
Each coroutine must increase this counter by 1 before it ter$$anonymous$$ates.
Periodically check if the counter has reached its final value (= number of coroutines)

avatar image Owen-Reynolds doublemax · Sep 13, 2016 at 02:03 PM 1
Share

That's called a Semaphore. It's the 100% standard way of waiting until several people are finished, as it appears in any Operating Systems textbook.

Well, except you usually count down -- add 1 when you start, subtract 1 when finished. That way the counter is how many people are still working, with a nice 0 meaning all finished.

avatar image doublemax Owen-Reynolds · Sep 13, 2016 at 02:19 PM 0
Share

Thanks, i even know what a Barrier class is ;)

$$anonymous$$y selfdoubts were more about whether there might be a Unity Coroutine "trick" that does the same.

Show more comments

1 Reply

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by Bunny83 · Sep 13, 2016 at 08:45 PM

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[i] = StartCoroutine(_Coroutine(i));
     }
     for (int i = 0; i < endValue; i++)
     {
         yield return coroutines[i];
     }
     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.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Owen-Reynolds · Sep 13, 2016 at 10:00 PM 0
Share

Right. That edit is what double$$anonymous$$ax suggested (and I mentioned usually counts down, as you have it.) I usually add to instances inside the loop, since I don't trust the coroutine to start right away.

A trick with this is you don't need to yield on the count. You could also just check if(instances

Also yes, I don't see this as an efficient design trick, but sometimes you just naturally want to run several coroutines. $$anonymous$$y last time was making several WWW requests and waiting until they all finished.

avatar image Phur3ouZ · Sep 14, 2016 at 02:07 AM 0
Share

Well your answer fitted my situation, however you said it's an unusual case, so it's more than likely I'm just incorrectly using coroutines for something that doesn't require it (it's just it was a solution that worked and I probably dug myself deeper into the rabbit hole).

I've edited the question for your interest. Just for my own learning, is there any better approach you would have taken?

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

6 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How to slow down large code? 1 Answer

Play animation 5 sec, stop for 5 seconds, repeat 0 Answers

Simplify this code 3 Answers

Using a while loop in coroutine as a contained Update function 1 Answer

Why is this coroutine only firing once? 3 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges