Coroutines vs Update

Discussion in 'Scripting' started by Staples, Nov 20, 2010.

  1. Staples

    Staples

    Member

    Joined:
    Jan 14, 2009
    Messages:
    221
    Hi guys, I haven't really used coroutines much, just wondering about performance.

    Let's say you have a unit with a 'poison' debuff that lasts for 20 seconds, and damages them every second.

    Are you better off using Update(), applying the damage when the time is appropriate (say nextDamage = Time.time + 1 second), or are you better off somehow doing this in a coroutine, perhaps in a while loop?

    As a second question relating to this, Is one or the other better for a multiplayer game? I don't think it would matter either way in this regard, but just thought I would ask.


    Thanks.
  2. Dreamora

    Dreamora

    Member

    Joined:
    Apr 5, 2008
    Messages:
    26,586
    For something like this which basically applies 1 event 20 times and then 1 a single time you better use coroutines as you can have a simple for loop with yield for 1 second and then just do the debuff and exit of it.

    update would take significantly more performance
  3. Staples

    Staples

    Member

    Joined:
    Jan 14, 2009
    Messages:
    221
    Thanks, at what point do you think you are better off using Update()? Even the poison was to be applied every 0.1 seconds would coroutines still be better?

    I guess at the end of the day Update() is better used for checking input and physics/movement?
  4. Dreamora

    Dreamora

    Member

    Joined:
    Apr 5, 2008
    Messages:
    26,586
    Update is then better if you need to check it each frame or if you need more complex branching / state handling where you can't rely on pausing.

    But as long as pausing is the primary thing you do, coroutines are always better.
    never forget, an update thats present will be called through a send message alike mechanism which isn't exactly lightweight, while a coroutine is just there and sleeping :)

    Especially on more limited devices like mobiles the difference can become impacting if you follow it on all objects
  5. Staples

    Staples

    Member

    Joined:
    Jan 14, 2009
    Messages:
    221
    Great, thanks for the tips.

    I noticed they used coroutines in the lerp example even to update the enemy units movement, I wouldn't normally have done this, but I guess there is no input being checked.
  6. Staples

    Staples

    Member

    Joined:
    Jan 14, 2009
    Messages:
    221
    Just a few questions extending on this.

    1) If you happen to have an update function running anyway, is it better to use that instead of creating separate coroutines.

    2) Let's say you are updating the players health, mana and stamina, regenerating them at separate intervals. Is it still more efficient to have 3 separate coroutines using infinite loops to update these values each tick, as opposed to a single Update()? I guess the Update() is still going to run much more often?
  7. ivkoni

    ivkoni

    New Member

    Joined:
    Jan 26, 2009
    Messages:
    978
    1) no
    2) it's hard to tell. If you really want to know you will have to test it in your case. I don't think there will be much of a difference. Coroutines though will result in much better looking code.
  8. Staples

    Staples

    Member

    Joined:
    Jan 14, 2009
    Messages:
    221
    Thanks. I guess another option is to have a single constant coroutine loop that runs at a specified interval, every time it runs you could check if it's time to regenerate the players health etc.

    I suppose 1 coroutine should still be better than 3 coroutines, depending on any extra complexity that it takes to manage the 3 tasks.

    Anyhow I'll just create separate coroutines for now, it's good that I found out about them earlier, otherwise I would have ended up using Update() for everything!
  9. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Messages:
    25,007
    Actually it's best to use InvokeRepeating where possible. I did a test on 5000 objects, where each one runs this:

    Code (csharp):
    1. private var i = 0;
    2.  
    3. function Start () {
    4.     InvokeRepeating("Test", .01, 1.0);
    5. }
    6.  
    7. function Test () {
    8.     i++;
    9. }
    That normally takes .03 milliseconds per frame, with spikes of 2.38 ms every second (when all 5000 functions run).

    Using this code instead:

    Code (csharp):
    1. function Start () {
    2.     var i = 0;
    3.     while (true) {
    4.         i++;
    5.        
    6.         yield WaitForSeconds(1.0);
    7.     }
    8. }
    also takes .03 ms per frame, but the spikes are 4.03 ms every second. Using Update:

    Code (csharp):
    1. private var timer = 0.0;
    2. private var i = 0;
    3.  
    4. function Update () {
    5.     if (Time.time >= timer) {
    6.         timer = Time.time + 1.0;
    7.         i++;
    8.     }
    9. }
    takes an average of .93 ms per frame (no noticeable spikes every second, since the overhead overwhelms whatever CPU time the actual code uses, even multiplied by 5000). At about 100fps, that's a total of 93 ms per second, whereas the coroutine is a total of 7.03 ms per second and InvokeRepeating is 5.38 ms per second.

    --Eric
  10. Staples

    Staples

    Member

    Joined:
    Jan 14, 2009
    Messages:
    221
    Thanks for that, seems a bit more elegant for things that are infinitely repeating as well. I suppose coroutines are still useful because of how you can use them.
  11. Staples

    Staples

    Member

    Joined:
    Jan 14, 2009
    Messages:
    221
    Just a question relating to the use of InvokeRepeating, if you had a function that was repeating and wanted to change the rate at which was repeating, can you just call InvokeRepeating again on the same function - I assume this will cancel the existing invokation and start a new one?
  12. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Messages:
    25,007
    Yes, coroutines are very useful for scheduling a series of events:

    Code (csharp):
    1. function Start () {
    2.     yield ShowTitleGraphic();
    3.     yield FadeTitleGraphic();
    4.     yield FadeInMainMenu();
    5.     // etc.
    6. }
    And other things where InvokeRepeating is too limited. (For one thing, you can't pass any parameters to functions called with Invoke.)

    You'd call CancelInvoke before doing InvokeRepeating again, otherwise you'd have it running twice, at two different rates.

    --Eric
    Last edited: Nov 21, 2010
  13. Staples

    Staples

    Member

    Joined:
    Jan 14, 2009
    Messages:
    221
    Thanks, yeah just realized that.

    I guess the performance difference is minimal and coroutines would be somewhat simpler for regenerating health if the rate can change. But usinng invoke just means that you need to re-invoke it when your rate changes, so not exactly a big deal if it means extra performance.

    I'm hardly up to the performance optimize stage yet, but it's nice to know these things so you can do it right to begin with, so thanks for running the numbers on them Eric.
  14. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Messages:
    25,007
    Yeah, basically if you can do the same thing just as easily with either coroutines or InvokeRepeating, then go with the latter. But both of them are a lot better than Update if you don't need something to run every frame so there's no point going through contortions to use InvokeRepeating if coroutines are better.

    --Eric
  15. tbryant

    tbryant

    New Member

    Joined:
    Aug 12, 2009
    Messages:
    17
    I'd like to have a routine run at a high rate, for example repeating every 1 ms, but it seems that InvokeRepeating ("FastUpdate", 0.0f, 0.001f);
    won't remain constant if the frame-rate is getting low. I take that to mean that the mean that it depends on the Unity Update()... First of all, is that true? Second, could I get around that with coroutines?
    not sure if this is the best thread, but it seems like the right people. :)
  16. Hodor

    Hodor

    New Member

    Joined:
    Feb 1, 2013
    Messages:
    1
    I just started studying Unity Script and the use of Coroutine instead of FSM is something that I'm having some trouble to understand.

    The C# compiler converts the IEnumerator into a state machine. Using a Coroutine in Unity is the same as using a state machine, but just easier to read to some programmers. You will still need to verify the conditions on every frame, even if you would like to do something just once.

    I understand that callbacks might be usefull here, but can you please explain why running a code in a Coroutine is better for performance than having a FSM in the update function?
    Last edited: Feb 2, 2013
  17. dkozar

    dkozar

    Member

    Joined:
    Nov 30, 2009
    Messages:
    1,395
    There is a more elegant way of doing this - the asynchronous way (without coroutines or constant Update checks).

    Check out this post on using a Timer.

    Note: this approach introduces no performance gain over the Update way of doing things: its purpose is a better written code.

    Example code:

    Code (csharp):
    1. public class TimerTest : MonoBehaviour {
    2.  
    3.     private Timer _timer;
    4.    
    5.     void Start()
    6.     {
    7.         Debug.Log("Start");
    8.         _timer = new Timer(1); // tick each second
    9.         _timer.Tick += TickHandler; // subscribe
    10.         _timer.Start();
    11.     }
    12.  
    13.     void TickHandler(Event e)
    14.     {
    15.         Debug.Log("Tick!");
    16.     }
    17.  
    18.     void OnDestroy()
    19.     {
    20.         Debug.Log("OnDestroy");
    21.         _timer.Tick -= TickHandler; // unsubscribe
    22.         _timer.Stop(); // stop the timer
    23.         _timer.Dispose(); // dispose?
    24.     }
    25. }
    Last edited: Feb 2, 2013