In Unity, when should I use coroutines versus subtracting Time.deltaTime in Update()?
Asked Answered
S

6

14

Below is a simple example of the difference I would like to highlight.

Using coroutines:

public float repeatRate = 5f;
void Start()
{
    StartCoroutine("RepeatSomething");
}
IEnumerator RepeatSomething()
{
    while (true)
    {
        yield return new WaitForSeconds(repeatRate);
        // Do something
    }
}

Using Update() and Time.deltaTime:

public float repeatRate = 5f;
private float timer = 0;
void Update()
{
    if (timer < 0)
    {
        // Do something
        timer = repeatRate;
    }
    timer -= Time.deltaTime;
}

When should I use one as opposed to the other and what are the advantages/disadvantages of each?

Succedaneum answered 27/4, 2020 at 17:13 Comment(0)
S
9

In most cases the answer would be.

In general the performance difference between Update and Coroutine is not relevant. Just follow the approach that suits you best, but use the much more performant MEC Coroutines instead of Unity Coroutine if you want to follow a Coroutine-like approach.

SIMPLE USAGE

As mentioned in the unity forum in general "Coroutines are useful for executing methods over a number of frames [and then forget about it]."

If you plan to use just a few of them (less than 10k?), then you're fine also with Unity Coroutines.

ADVANCED USAGE

At the moment Unity supports Task/Async, but the performance is still quite low. So you might think about using Coroutines to simulate Async functionality.

In this case you might even use Coroutines to remove all (or most of) your Update loops, such as in the example you posted.

This is useful in terms of performance, especially in your specific case, because when you use the Update loop you keep costantly checking for the if (timer < 0) even when you're doing nothing. And even an empty Update Loop is still a performance issue.

On the other hand you might just start and stop Coroutines when an event happens. And when the Coroutine stops the performance cost becomes 0.

If you want to follow this method I strongly suggest to use MEC coroutines that removes all the performance issues caused by Unity Coroutines (and have the same functionality).


IN CONCLUSION

  1. In most situation this difference of performance is not relevant
  2. MEC Coroutines are a bit more performant than the Update loop
  3. Update loop is generally more performant than Unity Coroutines
  4. Unity Coroutines should be used only for simple timed tasks that happens rarely

PS: this answer about unity coroutine might help you understanding how they work in depth.
PPS: this old answer might give you further insight, but it is a bit outdated, especially when it talks about the garbage collection.

Samathasamau answered 28/4, 2020 at 7:34 Comment(2)
++ for MEC Coroutines. If you're going to use them, use MEC.Godwit
I have a hard time integrating MEC coroutines with UnityTest. Can you help me?Lunseth
P
5

Just wanted to post here that, I tried MEC coroutines lately, and it's more performant than Unity coroutines if we're checking for latency and response times, but it's only matters when you run so many of those (like at least above 10K simple ones), most likely you never will or should. However, GC's work with Unity's coroutines have been fixed ever since, and actually MEC coroutine gives much more work to GC now, like 10 times more! So I was incrementing a number with coroutines, giving one increment to a new coroutine, just like the performance test that the developer did in 2016, and Unity's coroutines held up the Playmode, but was making in my case 68MB garbage, while MEC ones did 0,73GB.... So I changed back my coroutines to Unity ones.

Ploch answered 21/10, 2021 at 13:11 Comment(1)
No wonder it's not popular… So Unity has officially improved their coroutines.Lunseth
A
2

The simple answer is use whichever is more readable (there's not a noticeable difference in performance as far as I'm aware). I would (usually) use Coroutines because that'll help keep your Update loop more organized and I feel they're generally a little bit easier to set up (you don't need to create a variable for your timer etc.)

Anthroposophy answered 27/4, 2020 at 17:29 Comment(0)
G
2

Never use Coroutines.

This will greatly improve how you solve problems, especially in a game engine, and avoid needless garbage creation, garbage collection and slow callings and other issues relating to interfaces and coroutines.

It will also mean you program faster and simpler, and it's easier to think about and reason about what's doing what, where, when, why and how.

Coroutines are an addictive drug that should be avoided as though they have no benefits. Because they have no benefits over thinking better about your program and writing it better.

Once you start using coroutines it's a bit like putting cream and sugar in your coffee. You'll always add a bit more of each as they somewhat go together, and it all seems to be enhancing things.

You'll eventually even compromise on coffee quality because its flavours no longer seem all that important. You've become addicted to dairy, sugar and coffee, not just caffeine.

You'll begin drinking too much, cause it goes down so easy now that you've mastered the recipe. It tastes so right it can't be wrong. But you'll be restless, stressed and not sleeping well, odd bits of fat will show up on your body and you'll be irritable among those you love most.

What seemed like a solution has become the problem. Then the really big issues begin showing up, in your health and mental well being.

All this can be avoided by simply drinking green tea and never using coroutines. Because the price you pay later, for becoming a coffee addict, simply isn't worth it.

Ever.

Godwit answered 27/4, 2020 at 19:33 Comment(3)
Although I agree with this answer and understand the reasoning, it would be nice to also add some references/performance metrics or common scenarios to help understand where the mess beginsDipterous
Very true about pointless opinion arguments. Since the time of this answer, I have found a very interesting talk from Unite 2019 that brings up the question of async vs coroutines after dotnet 4 was integrated. Lots to learn from it.Dipterous
This is, in my opinion, the only correct answer. I've been writing code in C# since it was a beta project and I can say that most things newer devs call "time saving" is just a disaster waiting to happen, and it always happens eventually. Learn SOLID, DDD, and C# and you won't have any need for stunts that diverge from how the language was intended, and you'll never waste a day hunting for your own bugs (just everyone elses).Celestial
M
1

To be completely honest, they will perform the same task. They will both execute every single frame (and in your case, check if 5 seconds have passed since their initial execution). However, there are a few key differences. Namely, the most important one, is execution order. Coroutines will always run after Update(). If you have, for some reason, something happening in Update() that needs to be refreshed in order for the Coroutine to be updated with the correct information, then this is important. But normally, this is not the case.

In conclusion, either one will complete your desired task, and it usually just comes down to a matter of preference and organization.

Meemeece answered 27/4, 2020 at 17:31 Comment(0)
P
1

With every yield, you're actually creating a new object as you say new WaitForSeconds(). However, the difference is still not that significant. On the other hand, coroutines are way more readable, especially consider the case that you need to use more than one yield in the same coroutine with different wait times, implementing such a thing in Update would make your code quite messy.

Potherb answered 27/4, 2020 at 17:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.