Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 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 kaiyum · Nov 09, 2013 at 08:43 PM · coroutineyieldflowexecution-order

Execution manner of co routine

Hi, these are my code

 using UnityEngine;
 using System.Collections;
 
 public class sample : MonoBehaviour {
 
     // Use this for initialization
     void Start () {    
     
     }
     
     // Update is called once per frame
     void Update () {
 
         if (Input.GetKeyDown("space"))
         {
             print ("called before coroutine");
             StartCoroutine("testCOR");
             print ("called after coroutine");
         }
         print ("this is end of frame.");
     
     }
     IEnumerator testCOR()
     {
         for(int i=0;i<3;i++)
         {
             print ("Now number is: "+i);
             print ("Just before coroutine");
             yield return null;
         }
     }
 }

When I press spaceBar just one time, the result pattern I am expecting is:

 ....................
 ....................
 this is end of frame.
 this is end of frame.
 this is end of frame.
 called before coroutine
 Now number is: 0
 Just before coroutine
 called after coroutine
 this is end of frame.
 
 called before coroutine
 Now number is: 1
 Just before coroutine
 called after coroutine
 this is end of frame.
 
 
 called before coroutine
 Now number is: 2
 Just before coroutine
 called after coroutine
 this is end of frame.
 
 called before coroutine
 called after coroutine
 this is end of frame.
 this is end of frame.
 this is end of frame.

In stead I am getting the following:

     ....................
     ....................
     this is end of frame.
     this is end of frame.
     this is end of frame.
     called before coroutine
     Now number is: 0
     Just before coroutine
     called after coroutine
     this is end of frame.
     this is end of frame. //why twice. Is unity taking two frames?
     
     Now number is: 1
     Just before coroutine
     this is end of frame. //where is "called after coroutine"? 
     
     Now number is: 2
     Just before coroutine
     this is end of frame.
     this is end of frame.
     ....................
     ....................

When I press spaceBar again, I got these:

 ....................
 ....................
 this is end of frame.
 this is end of frame.
 called before coroutine
 Now number is: 0
 Just before coroutine
 called after coroutine
 this is end of frame.
 this is end of frame.
 
 Now number is: 1
 Just before coroutine
 this is end of frame.
 
 Now number is: 2
 Just before coroutine
 this is end of frame.
 this is end of frame.
 ....................
 ....................

The dots means I am getting "this is end of frame." line continuously forever.

So, each time I press spaceBar, I get similar pattern. Probably coroutine does not work like the way I thought. But how does they execute? I need to know this. It is now such a mystery to me now. I thought like these:

when you encounter yield statement, control flow jumps from coroutine to next line of "startCoroutine()" and then finishes rest of the jobs in update() method. After finishing, flow returns(of course after lateUpdate and other stuffs) to again Update method. This time flow goes to co-routine again. But "with having previous state". Loops goes on and on until the "forLoop" does not let it go further. Then flow again returns to update method and completes the rest jobs to render that frame. This happens whenever something triggers the coroutine.

If we use coroutine's yield like "waitforFixedUpdate" manner,then execution resume on next physics change instead of next frame. If we use "waitForEndOfFrame", then execution resume after LateUpdate and rendering(GUI drawing?) on next frame in stead of next frame on "update" method. That means coroutine will not execute while we are on update method if we use "waitForEndOfFrame". Rather it will execute when we finish drawing our frame.

So those were my thoughts on coroutine. Clearly I was wrong. But what is right regarding Coroutine. Please shed some lights on it. It is driving me crazy!

Comment
Add comment · Show 2
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 Huacanacha · Nov 10, 2013 at 06:44 AM 0
Share

Check out unitygems.com/coroutines/

avatar image kaiyum · Nov 10, 2013 at 02:03 PM 0
Share

Actually I read it a while ago. The resource is quite good. Sadly it fails to explain in depth of control flow or I have failed to understand it properly. Anyway I recommend everyone new to coroutine to first check Unity Docs about coroutine And then unityGems docs.

2 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer Wiki

Answer by kaiyum · Nov 10, 2013 at 04:19 PM

So I will be answering my own question. Ok. the concept of program counter(PC) is very important. When you run any computer program, binary executes line by line. "Something" reads a line and executes it, then moves it to next line. This "something" is called PC. It is actually a pointer that holds the address of "next instruction to execute". Lets look at the following simple C++ program.

     Line 1 #include<iostream>
     Line 2 using namespace std;       
     Line 3 void anotherMessage()
     Line 4 {
     Line 5 cout<<"yet another message";
     Line 6 }       
     Line 7 int main()
     Line 8 {
     Line 9 cout<<"Hi there!";
     Line 10 showMeMessage();
     Line 11 return 0;   
     Line 12 }        
     Line 13 void showMeMessage()
     Line 14 {
     Line 15   cout<<"this is the message";
     Line 16 }

Ok.Lets think as a machine. First I will look on a file called "iostream.h" sothat I will know how to print something. Then with "using namespace std;" I realized all the names are standard. Meaning "cout" "endl" etc means something which is standard. If we do not do it then I might say cout is for "a command to get out of comod"!. This is pre-processing. After preprocessing, actual execution happen first at main method. I shall not look at "void anotherMessage()" or "void showMeMessage()" first. First I will look at main method. Main is our entry point. So PC will be at first on "main()" method. Then I first print "hi there". Then I encounter a showMeMessage() method. Then I go straight its definition. After that I print "this is the message". Then I return 0 and exit. So the pattern of PC by line number is: 1>2>7>8>9>10>13>14>15>16>11>12

Now I will explain how coroutine execute as same manner. head up to my first code. Carefully get the line numbers. This frame we are at line number 12, update method. Then 13>14. Are we pressing spacebar now at 14? Lets say we not. So jump into 20. On the next frame, program detect we pressed spacebar. So what will happen?

12>13>14>15>16>17 then it will find a coroutine and will execute it. So after 17,it will be on 23. 23>24>25>26>27>28>29. On 29, we see null(if we do not,lets say we find another coroutine after return. Then PC will go there. You can nest endless coroutine I guess), so we go to 30 and then:

30>18>19. Mark this position. After 19, we are out from the code block of if statement. 19>20>21>22

Thus on this frame(the frame program detects a "spacebar press"), we have this pattern for the sample code: 12>13>14>15>16>17>23>24>25>26>27>28>29>30>18>19>20>21>22

Now on the next frame, program will not detect a "spacebar press" if we do not hit spacebar again. For simplicity, lets assume, we haven't hit any key. So what will happen on next frame. Remember we haven't completed for loop as we returned an yield when we have i=0. So when will we resume. How will PC move this time?

12>13>14. it does not detect any spacebar hit, so code block of if statement "will not execute". Thus after 14, 20>21>22.Wait a min,we haven't resumed our coroutine. Yes gentleman, now we will resume. So after 22, we will not move to next frame. Rather,

23>24>25>26>27>28>29>30. After this we will move on next frame. On next frame we will not register any spaceBar. So, similar pattern will goes on and on until we are done with coroutine(i>=3).

One question remain, if we constantly pressing spaceBar.Meaning, on each frame we detect spaceBar hit, what will happen?[edit: at first, it will complete first invocation. When first coroutine instance is complete, it will go to second one. And thus it goes on and on] After first coroutine invocation, next invocation will wait for finishing of current one? or things will go mess up? Probably another guru will clear up. And I can do some experiments!

So the summery of this long post is: After first yield, it will resume when next frame will complete everything, not in the middle!

EDIT 1:

I have found some interesting ideas. It is about nested coroutines.

what will happen when you do like:

 yield return StartCoroutine("anotherCOR");

when anotherCOR() looks like similar to:

 IEnumerator anotherCOR()
 {
  for(int i=0;i<3;i++)
  {
   print ("Now number is: "+i);
   print ("Just before coroutine");
   yield return null;
  }
 }

Well on each invocation of testCOR(), at first anotherCOR() has to be completed. This means: for i=0 of testCOR(), at first i of anotherCOR() has to be 0-1 and then 2. Only then next invocation of testCOR will happen. I guess we can nest another like:

 IEnumerator anotherCOR()
  {
    for(int i=0;i<3;i++)
    {
     print ("Now number is: "+i);
     print ("Just before coroutine");
     yield return StartCoroutine("yetAnotherCOR");
    }
  }

Much like nested if-else. I am thinking its practical use. What it can be?!

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 aldonaletto · Nov 10, 2013 at 04:35 PM 1
Share

From my tests, the sequence is:

1- StartCoroutine: the coroutine executes until a yield is found, when Unity leaves the coroutine stopped and resume execution of the caller code right after the StartCoroutine instruction.

2- This frame is rendered;

3- In the next frame, after all Updates and LateUpdates, Unity resumes execution of the stopped coroutine, and runs it until a yield is found, when the coroutine again gets stopped and Unity takes care of the next pending coroutine. When all coroutines have been serviced, Unity goes to step 2, and so on.

avatar image kaiyum · Nov 10, 2013 at 04:49 PM 0
Share

exactly same sequence I am getting!

avatar image
1

Answer by Berenger · Nov 10, 2013 at 03:11 PM

StartCoroutine will create an instance of the coroutine that will run it's course independantly of the Update function. If you press space several times, you'll have several instances. If you want an in-depth explaination, check this out : http://www.altdevblogaday.com/2011/07/07/unity3d-coroutines-in-detail/

For your problem, insert the prints "before" and "after" inside the for loop of the coroutine.

Comment
Add comment · Show 1 · 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 kaiyum · Nov 10, 2013 at 04:14 PM 0
Share

From my little observation, coroutine always resume after update function. Is this true completely? If I have several coroutines instance triggered, then all instance will be executed one after another,right?

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

19 People are following this question.

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

Related Questions

How to properly use Yield for a coroutine? 3 Answers

Understanding yield inside a for or a while loop 2 Answers

yield on a www never completes 10 Answers

Var change between 2 RPC calls / Coroutine problem 1 Answer

How to start at a specific coroutine? 0 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