What is the best between StartCoroutine or InvokeRepeating.

Hey Guys,

I’m wondering what is the best if I want to call a method every 0.5 seconds or even a smaller amount of time. I know I can do it with both StartCoroutine and InvokeRepeating but I wonder what are the advantages/inconveniences of both method and also performance wise, which is the best. Thanks a lot for your time and have a good day!

Claude

If you have 1 enemy shooting a bullet say every 5 seconds then you wont notice any difference between Invoke or StartCoroutine. However if you have say 30 enemies shooting complex bullet sequences every 5 seconds then Invoke & InvokeRepeating can have a huge effect on performance depending on the device its running on.

I would say always use StartCoroutine. ie.

// wait 3 seconds then shoot
Invoke("Shoot", 3f);

void Shoot() {
    // shoot stuff
}

.. becomes ..

StartCoroutine("Shoot");

IEnumerator Shoot() {
    yield return new WaitForSeconds(3f);
    // shoot stuff
}


and


// wait 5 seconds then shoot every 2 seconds
InvokeRepeating("Shoot", 5f, 2f);

void Shoot() {
    // shoot stuff
}

.. becomes ..

StartCoroutine("Shoot");

IEnumerator Shoot() {
    yield return new WaitForSeconds(5f);

    while (true) {
        // shoot stuff
        yield return new WaitForSeconds(2f);
    }
}

InvokeRepeating is easier to learn and use, but, obviously, can only do things at regular intervals. Any weird multi-step, fade-wait-unfade stuff, you have to use a coroutine for (not because of a rule – because there’s no way to twist InvokeRepeat to do that stuff.) I’d say, anything you can use InvokeRepeating for, go ahead and do that.

I’d guess that InvokeRepeating is really just running StartCoroutine for you, with a free “every X seconds” delay. So it really makes no difference which you use.

I found this on a comment of a gamasutra article: “The Invoke* functions are implemented by using reflection. Reflection have very huge overhead when calling and should be avoided. Coroutine, on the other hand, has very little or no overhead (depending on which StartCoroutine version you using), so, it is a better alternative for Invoke*.”

In addition to what others have said (Invoke using reflection which causes a significant impact on performance, and being extremely error prone by using strings to call methods), there is another very big issue: Invoke and InvokeRepeating are based on Time.timeScale.

So if you use them, for example, in a settings menu that is shown during pause, with pause being implemented by setting Time.timeScale to 0, methods called by invoke will simply never be called because the time never “passes”.

So, I would strongly recommend to never use Invoke or InvokeRepeating and always use Coroutines or another approach instead.

Hey There,

As emongev was saying Invoke uses reflection to call your functions. It’s not the fastest thing in the world but then again Unity runs on reflection. StartCoroutine uses and ienumerable and an ienumerator to iterate over a list of steps that you define.

One huge difference is that a Coroutine is a time share, meaning it acts like a thread even though it’s not. It allows you to wait for a process to finish without stopping execution of your project. When that process is done it picks up where it left off.

(Super basic explanation of what it really is doing)

.

** My Advice **

Never use Invoke or Invoke Repeating. It can make your code very difficult to debug. You can very easily implement a system using update.

Another consideration is code fragility. If you use InvokeRepeating() you have to pass the target method as a string. This means it’s a risk of a typo or future renaming of the target method.

Although StartCoroutine() can take the target method as a string, it can also take the coroutine as its argument. This is my recommended approach.

Taking the example by @chazzysb, I would write it:

 // wait 3 seconds then shoot
 Invoke("Shoot", 3f);
 
 void Shoot() {
     // shoot stuff
 }
 
 .. becomes ..

// declare a coroutine variable
private IEnumerator coroutine;

void Start() {
    // assign the coroutine variable
    //NB you can pass args to a function that has args
    coroutine = Shoot(); 
    ...
}

// Here's where I want to invoke it
StartCoroutine(coroutine);

 IEnumerator Shoot() {
    // same as what chazzysb put
   ...
}