Search Unity

InvokeRepeating VS Coroutines [Performance]

Discussion in 'Scripting' started by Rukas90, Sep 24, 2017.

  1. Rukas90

    Rukas90

    Joined:
    Sep 20, 2015
    Posts:
    169
    Hello everyone.

    I was wondering, what is better to use InvokeRepeating or Coroutines? I want to optimize my scripts and instead of calling stuff every frame per seconds inside the Update() function only call the specific function for example every 0.25f seconds. So I decided to use either InvokeRepeating or Coroutines. But I don't know what is better in terms of performance. I wrote couple of simple script. Which example is more optimized?

    InvokeRepeating:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class CameraReposition : MonoBehaviour {
    6.  
    7.     [SerializeField] private Camera[] cameras;
    8.     [SerializeField] private Transform pos;
    9.  
    10.     public bool forceRePosition;
    11.  
    12.     void Start ()
    13.     {
    14.         InvokeRepeating("ForceRePosition", 0f, 0.2f);
    15.     }
    16.    
    17.     void ForceRePosition ()
    18.     {
    19.         if (!forceRePosition) return;
    20.         cameras[0].gameObject.transform.position = pos.position;
    21.         cameras[1].gameObject.transform.position = pos.position;
    22.     }
    23. }
    Coroutines:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class CameraReposition : MonoBehaviour {
    6.  
    7.     [SerializeField] private Camera[] cameras;
    8.     [SerializeField] private Transform pos;
    9.     [SerializeField] private float WaitTime = 0.2f;
    10.  
    11.     public bool forceRePosition;
    12.  
    13.     void Start ()
    14.     {
    15.         StartCoroutine(ForceRePosition(WaitTime));
    16.     }
    17.    
    18.     IEnumerator ForceRePosition (float waitTime)
    19.     {
    20.         while (forceRePosition)
    21.         {
    22.             yield return new WaitForSeconds(waitTime);
    23.  
    24.             RePosition();
    25.         }
    26.     }
    27.  
    28.     public void RePosition ()
    29.     {
    30.         cameras[0].gameObject.transform.position = pos.position;
    31.         cameras[1].gameObject.transform.position = pos.position;
    32.     }
    33. }

     
    hopetolive and Meany747 like this.
  2. dadude123

    dadude123

    Joined:
    Feb 26, 2014
    Posts:
    789
    Both have considerable overhead (when compared to a custom solution).

    If you want the absolute maximum performance, you can do something like this.

    1.) let all your objects implement an interface. lets call it IRepeatedInvoke which just contains:void Invoke();

    2.) have a manager object that has different lists of all the IRepeatedInvoke objects (or a custom priority queue implementation, but lists are easier and straightforward). The manager uses the normal unity Update() message to pulse all elements (calling Invoke on them) when their time intervall has been reached.

    3.) when an IRepeatedInvoke is created, it registers itself with the manager, calling something like timeManager.RegisterRepeated(this, Interval.Short); or something.

    The reason why this is especially fast is because every crossing of the native <-> managed barrier takes a little time.
    That means if unity has to call into your C# Update function for 100000 objects that would be way slower than if unity just had to call Update on one object, which in turn dispatches the Update to the right objects (because as you've noticed some objects might not even need to be updated every frame, but instead maybe just every second or so).

    Alternatively you could make different interfaces for the different durations.
    So IInvokeEverySecond, IInvokeThreeTimesPerSecond, and then put them into the right list in your manager that way. But that is bad design (marker interfaces) and in the end that would be more trouble I guess.
     
  3. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Just use the profiler to determine what's "better".
     
    Ziplock9000, Rallix, Kamodo13 and 4 others like this.
  4. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    It kind of sounds like coroutines are better from this:
    http://answers.unity3d.com/question...invoker.html?childToView=478166#answer-478166

    They are also a lot more versatile. I read someplace that it's faster to call the function than to use the string for starting it, but only the string allows you to stop it in code. Anyway, from a versatility standpoint, there is a lot more you can do with a coroutine so even if it was even up I would choose coroutine.

    I don't think I would use one to slow down camera positioning, though. They are more useful when you have a lot of AI enemies that need to do distance checks, etc.
     
    Last edited: Sep 24, 2017
  5. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
    You can stop a coroutine without using the string version, you just have to set it up correctly.

    There is also this asset for free https://www.assetstore.unity3d.com/en/#!/content/54975 which is suppose to be better than Unity's coroutines.
     
    idbrii likes this.
  6. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    That was interesting. I'm a little leary about assets because if there is a new version of Unity you can have all kinds of problems that you didn't create. It sounds like there is a large speed improvement though, so I'll keep it in mind if I have a problem with speed.
     
    twitchfactor likes this.
  7. simonlvschal

    simonlvschal

    Joined:
    Nov 17, 2015
    Posts:
    266
    that person who wrote that sounds like he doesn't have exactly everything known. InvokeRepeating can do just as much as Coroutines. if not more and also is more controllable in my opnion. basicly invokeRepeating is just a way of doing something outside update loop.. and you can easily control it to the point where u have alot of rules set up before invokeRepeating happens.
     
  8. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,741
    A pretty big downside of InvokeRepeating is that you have to pass the method to Invoke via string, this makes it much more prone to bugs, and you can not pass parameters on to to the method either
     
  9. BlackPete

    BlackPete

    Joined:
    Nov 16, 2016
    Posts:
    970
    ^ That. It's easy to screw yourself when you go and try to refactor and rename the function.

    I avoid Invoke and InvokeRepeating for exactly that reason.
     
    mopthrow, Foxeh-3 and SparrowGS like this.
  10. ErayT

    ErayT

    Joined:
    Dec 13, 2013
    Posts:
    20
    Yeah that changes everything....
     
  11. zHaytam

    zHaytam

    Joined:
    Jan 4, 2019
    Posts:
    3
    You can use
    nameof(...)
    to fix that.
     
  12. Tarodev

    Tarodev

    Joined:
    Jul 30, 2015
    Posts:
    190
    Yes, this removed a major downside. Good tip!
     
    LapidistCubed likes this.
  13. nineswordz

    nineswordz

    Joined:
    Sep 23, 2019
    Posts:
    12
    I encountered a problem with Coroutines and I can't stop it immediately (Instantiating objects but there's always one that doesn't stop, the final spawn object). Then I switched to InvokeRepeating and that solved my problem. My game/code is very basic so I guess its fine not using IEnumerate.
     
  14. NikoBay

    NikoBay

    Joined:
    Aug 15, 2018
    Posts:
    39
    this is an interesting idea. Is there any further source online about this that I can learn more?
     
  15. meMUmar

    meMUmar

    Joined:
    Oct 18, 2016
    Posts:
    4
    @dadude123 sounds good.... Can you please refer me some basic implementation... I would like to try it.... Thanks
     
  16. Avalin

    Avalin

    Joined:
    Oct 12, 2018
    Posts:
    98
    Hmm, I would very much like to know as well what performance-wise is best to do between InvokeRepeating and Coroutine, now that "nameof" has finally been implemented (or I learnt about it). Am I better off changing my coroutines to InvokeRepeating where possible?
     
  17. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    nameof just turns your function names into strings. While it has benefits during development (like making typos unlikely & not breaking when you automatically refactor), you'll still be accessing the method via a string in runtime and therefore performance will be exactly the same as it was before.
     
    Bunny83, PraetorBlue and Avalin like this.
  18. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    Nope, Coroutines are still better and more flexible:

    - You can pass whatever parameters into the coroutine you want
    - You can use all of the yield xxx directives
    - You can track and cancel individual coroutine executions by tracking the returned Coroutine or IEnumerator object.
     
    Bunny83, Avalin and StarManta like this.
  19. Ziplock9000

    Ziplock9000

    Joined:
    Jan 26, 2016
    Posts:
    360
    Disregarding flexibility, when you say "better" do you mean more performant? Have you done any tests?
     
  20. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    I'm not referring to performance specifically, I'm referring to compile-time safety and the ability to save a reference to a specific coroutine to be able to stop it.

    Regarding performance though, reflection is notoriously slow.
     
    Ziplock9000 likes this.
  21. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    The second answer here, and in the comments, says Invoke is much slower in their test: https://answers.unity.com/questions...oker.html?childToView=1794660#comment-1794660.

    It's from 5 years ago, but I suspect that Invoke and InvokeRepeating are beginner shortcuts for those who haven't learned coroutines. There may have been no reason to try to speed them up since then.
     
    Ziplock9000 likes this.
  22. Ziplock9000

    Ziplock9000

    Joined:
    Jan 26, 2016
    Posts:
    360
    After doing further research I've found other people 2018-2019 running tests and the overwhelming consensus is that coroutines can be considerably faster when a lot/frequently used. Case closed as far as I'm concerned.
     
  23. Zorkind

    Zorkind

    Joined:
    May 4, 2015
    Posts:
    55
    Ziplock9000 likes this.
  24. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
    I don't see the use case currently, personally. If I'm needing to manage that, I'd probably have a manager class that is checking and maintaining that where I can be running a coroutine if I need to.

    Even if I didn't want to go that route, depending on the object, you can turn off different things other than a gameobject or script to "disable it". For example, disabling a canvas is suppose to be more performant than disabling the gameobject. (I found this in an article once that I think Unity put out). And can still turn off that UI that way. Or, turning off a renderer or collider.

    Now, this is just saying what I would do. If someone can convince me the disadvantage of using InvokeRepeating can be outweighed by some advantage, I'd definitely look into it.
     
    jmcgraw961 likes this.
  25. mkShogun96

    mkShogun96

    Joined:
    Jun 16, 2015
    Posts:
    1
    This was actually a pretty interesting read. I think when it comes to simplicity (and learning unity scripting) invoke repeating is a pretty good way to use repeating functions (with start delay and repeat interval). I was really surprised that unity had such a nice easy way to do this (as I know from past programming experience working with Task Delays etc is always messy). I have not had the chance to play around with Coroutines yet, but seems very similar. I like the simplicity of InvokeRepeating but as many have pointed out using Reflection is pretty taxing, so in a much bigger project @dadude123's proposal seems to be a very good approach. I'd love to give it a try one day!
     
  26. andrew_pearce_

    andrew_pearce_

    Joined:
    Nov 5, 2018
    Posts:
    169
    I came across to InvokeRepeating() and found it's very interesting to simplify the code and make it easier to read. However, I would like to know, do we waste performance only ONCE when we setup function call from its string name or it's MULTIPLE times (for every repeated call)?

    IMHO it should be only once and if that's true then this is really cool way to setup some simple logic, which needs to be called every 0.1-3 seconds. If InvokeRepeating() is called only few times during the lifetime of the object (which varies from couple of seconds to minutes) is really good trade of performance to code simplicity.

    How many lines it will take to declare the IEnumerator with infinite while loop or add private property to track the time interval which will be used in Update() method. The only downside I can see so far is that it cannot accept parameters and may be it's worth to create your own static method which will accept Action delegate. The use case of InvokeRepeating() is limited to rapid prototyping, debugging.
     
    Last edited: May 20, 2022
  27. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,002
    Well, we don't know how Unity handles this specifically on the native side. However my guess would be as well that it should be a one time overhead. In the end an InvokeRepeating call will end up as an object in some sort of collection on the native side which has to pair the method that should be called with the timeout / timer. Unity staff has repeatedly said when Unity calls a managed method, they "sort of" use reflection which however is faster than normal reflection. In the end the native code owns the CLR our managed code runs in.

    Though it's of course possible that they don't store the method reference but just the string and essentially use the SendMessage mechanic internally. While this is possible, I don't think they have gone down that route.

    I wouldn't care much about the "number of lines". Focus on the actual features you need.

    It should be noted that when using a coroutine, you can cache the WaitForSeconds object at the start of the coroutine and reuse the instance when the time doesn't change. This removes the memory allocation and the coroutine becomes GC neutral once it's running. If you need a garbage free waitforsecond solution, I posted a hacky solution over here. It's hacky because it relies on the current internal implementation of the WaitForSeconds class. However it hasn't changed over the last 12 years, so...

    If you're looking for a custom FixedUpdate solution, you may want to have a look at my old CustomFixedUpdate class. I had it on the wiki but since the wiki is down I put it in my utilities github rep. Originally it was a response to this question. Here's an archived version of the wiki.
     
    TeHuster and andrew_pearce_ like this.
  28. andrew_pearce_

    andrew_pearce_

    Joined:
    Nov 5, 2018
    Posts:
    169
    Thank you so much for your CustomFixedUpdate class, that should be enough, I like it! Also, thanks for a tip regarding caching WaitForSeconds object. Even though it looks obvious, I never thought about it as it was kind of automatically natural to instantiate a new one within a waiting loop.

    p.s. Oh and it's worth to check your other helper classes on a github, I am sure there will be some other interesting solutions there =)