I wanted to try to get this message out clearly and broadly.
Lately we have seen a number of very convoluted uses of co-routines in questions in Unity Answers and the question always seems to start with the same statement:
“I used co-routines because I didn’t want to slow my code down with code in Update…”
Be very clear. There is no magic in coroutines.
The reason loading your Update down with unnecessary work slows your program is because that work gets done every frame. If you run a co-routine at the same rate doing the same work, you have gained nothing. Worse, you have added a context-switch overhead to each run and potentially made the problem worse.
There is no magic to either Update or Co-routines. The point of the warning about Update is that you should avoid polling, anywhere, at all costs.
What about update being called through reflection? I have heard that it’s slow in this way. I’m not sure how this would compare with coroutine overhead. Does this reflection get used every frame, or does it get used once and then it’s like calling a normal function every frame after?
Either way, it’s probably rather insignificant as a performance cost. And this question probably sounds quite dumb, but I’m not very experienced with how reflection works at this point.
Even though there is a overhead in Unity for built-in magic methods like Update, it is certainly not the kind of optimizations that should be used.
To me it is just another example of premature optimization from inexperienced programmers who try to find the absolutely best and fastest method, but fail to see the big picture.
A coroutine running every frame is slower than Update running every frame. It can still make sense to use coroutines every frame (e.g. it’s trivial to delay stuff when needed, unlike Update), but speed isn’t one of the reasons in that case.
I don’t know the internals of Unity, but I have written other code that is based on reflection.
The slow part of reflection is generally looking up and finding the method. Once found, it is very cheap to invoke.
Well written code that has to call the same method over and over reflects once to find it and then caches it. i have to believe Unity is at least doing that. Seeing as they have control over the VM they may be doing other Unity specific things to optimize as well.
I use CoRoutines sometimes and did indeed see performance gains when I ran code every ~3rd frame from a CoRoutine. Although Garbage Collection might have been higher. That was way back on Unity 3 though. Subscribing to see what others say.
Funny you say that, because coroutines are actually implemented with ‘magic’. Sure… it’s just a compiler generated state machine, but until you’ve dug into it it is indeed magic.
Sure, if you’re code is exactly the same as an Update. However Coroutines lend to a different kind of thinking which can be quite beneficial - an optimisation in paradigm can be worth many in pure cycles. An update cannot wait for seconds, it cannot be stopped or paused, it cannot be scheduled, it cannot easily represent a state machine etc.
I agree with your main point - a coroutine that simple functions like an update in and of itself has no noticeable performance gains for any practical purpose I can think of. However, there are differences and understanding these differences can lead to a more nuanced response.
They are magic dammit! Why can’t some people just believe in the magic?! There are tons of young wizards and sorceresses out there and you are shattering their reality!
Coroutines use a well defined and reliable mechanism from .net. On the other hand Update, FixedUpdate and all the other built-in methods are much more magic at least from a technical point of view. They are based on reflection and it is extremely easy to get into a situation where you are not getting a single error message pointing you to the cause of the issue. Those situations may e.g. be that you use “OnColisionEnter” or “update”.
InvokeRepeating is one of the ugliest methods that exists in Unity, because it only allows you string based invoking. It would need to be significantly faster than any other approach, before I would even consider to use it.
Not really…you can implement logic so that the effects are similar, but it’s not as easy as coroutines.
InvokeRepeating is indeed faster than Update and coroutines, and while having to use a string is annoying, it’s the simplest possible method of making something happen at timed intervals.
What I meant is that it is trivial to create a reusable InvokeRepeating that only needs to be implemented once. You just spend that little amount of work once.
If I can decide between a little bit of performance and compile time warnings, I will always prefer the latter. With every error that can be caught at compile time, we can avoid a lot of debug time.