What is better for performance in Unity: Custom Timers or Coroutines?

Hello everyone,

I’m working on a game where many actions like dashes and jumps involve delays or timed effects. I’m debating which method would be best for handling these timings: custom timers or Unity coroutines.

My scenario:

  • Many entities (player and enemies) need individual timers for actions like dashes, jumps, and other temporary effects.
  • I’ve heard that coroutines can introduce some overhead when many of them are running simultaneously.
  • On the other hand, custom timers using Time.deltaTime seem like a more performant alternative, especially when dealing with a large number of entities.

Questions:

  1. Which method is better for performance when having many simultaneous timers in the game?
  2. Do coroutines have noticeable performance overhead when running in large numbers, or is the difference minimal?
  3. Are there scenarios where coroutines are definitely the better choice? And when should I prefer using custom timers instead?

I’d appreciate any insights or recommendations!

Thank you in advance!

  1. Custom timers likely are more performant. Especially starting coroutines and calling new (eg new WaitForSeconds) generates garbage. This depends on the exact implementation of course
  2. If one has overhead and garbage, more will just increase that
  3. Coroutines can be a bit more flexible and easier to grasp for many. In my opinion for entities, I suggest setting up a state machine. Then each state can check its state and run timers in their own OnUpdate/Tick methods. This sounds like it is a win in both code architecture and performance

Unsolicited advice: If you’re thinking of thousands of entities, maybe consider ECS

2 Likes

In general, you shouldn’t worry about performance unless there is an actual performance problem. Even if one method is faster than another, the difference may not matter because those methods might not be the bottleneck. They could be waiting on other processes to complete, making their speed irrelevant. Additionally, the performance difference might be negligible compared to the impact of other parts of your code.

That being said:

Timers are likely the better choice, as coroutines can generate garbage, but this ultimately depends on the timer implementation.

The answer depends on several factors:

  • What do you mean by “large numbers”?
  • What other code is executed by the components using these timers?
  • How do you define “minimal”?
  • What is the target hardware?
  • What type of game are you developing?

Also the performance hit may be due to being slower, or being faster but creating more garbage which means slower at certain points where the GC collects that garbage.

This is a very broad question, with different answers not only between timers and coroutines but also between different implementations of timers.

The only scenario where coroutines might be a better choice is if you’re short on time and unfamiliar with creating proper timers, so you opt to use what you already know. In most other cases, I believe timers are the better option, not just for performance reasons but also because they offer greater flexibility. Timers can be enhanced with features that are difficult or even impossible to implement with coroutines, such as pause/resume functionality, adding time to an active timer, or executing callbacks.

If you are interested check my post about timers: Various Timer Implementations in Unity and the github repository with the three mentioned timer implementations: https://github.com/meredoth/Unity-Timers

Finally, when it comes to performance-related questions, actual results are always more reliable than theoretical discussions. You can use Unity’s Performance Testing Package for Unity Test Framework to test the performance of different implementations. For isolated methods/code I think it serves better than the profiler.

EDIT: Also don’t use timers by adding/subtracting Time.deltaTime, because the float precision errors accumulate over time. Just check the time now compared to the time you started the timer.

4 Likes

Thank you very much for your detailed response and the helpful insights! I really appreciate your point about not worrying too much about performance unless there is a noticeable issue, and I agree that it’s often more about identifying where the actual bottlenecks lie.

What stood out to me most was your suggestion to compare times directly instead of relying on Time.deltaTime for timers. I hadn’t thought about the potential floating-point precision errors that could accumulate over time when using Time.deltaTime. This is an important consideration that I’ll keep in mind moving forward, as it could definitely make a difference in the accuracy of long-running timers.

Thanks again for sharing this valuable advice – I’ll definitely take it into account when optimizing my code!

2 Likes