What are the Pros and Cons of using Coroutines?

What are the pros and cons of using coroutines in terms of memory allocation, expensiveness, and speed?

Why I’m asking is because I was reading up on OnTriggerStay, and it mentioned it could be called using coroutines.

“OnTriggerStay can be a co-routine, simply use the yield statement in the function.”

So I went ahead and opened up one of my game and changes all the OnTriggerStay to coroutines. The end result was an incredibly low FPS of 15, compared to at least 30FPS when I use it as a normal function.

IEnumerator OnTriggerStay(Collider other)
{
currentAIState.OnTriggerStayState(other);
yield return new WaitForFixedUpdate();
}

Looking at the profiler, I noticed a huge amount of GC allocation constantly being added into Physics.TriggerStays.

Figuring it was because of the new keyword, I changed it to the following.

IEnumerator OnTriggerStay(Collider other)
{
currentAIState.OnTriggerStayState(other);
yield return null;
}

However, it was still giving a GC memory allocation that would reach into the MBs, as well as drop the FPS of my game.

Why does this happen, and what use is the coroutine in OnTriggerStay(), if it gives FPS issues.

Testing out OnTriggerStay as an enumerator in a simple test scenario with new WaitForFixedUpdate(); generates no garbage allocation, and does not appear to effect the performance of my test scene. The issue you are seeing is likely due to whatever your “currentAIState.OnTriggerStayState(other);” is doing, which appears to be generating a lot of garbage. Try enabling deep profile to see where the issue truly lies within that function that you are calling every fixed update.

It appears there are no cons associated with using OnTrigger as an enumerator/coroutine. Although since I believe that it is called every fixed update anyway, a possible con would be misuse / errors in physics due to non-fixed-time responses (compared to fixed update) if using WaitForSeconds(#) or return null;

If you show us the other function that is being called, it would help to identify the performance issue you are experiencing.

What is OnTriggerStays? Isn’t the method supposed to be OnTriggerStay?

Also, the method will be called every frame for every collider that’s touching the trigger. I’m not sure how the internals work, but it would seem that you would potentially get a new coroutine created every frame if you’re using yield. But that’s a complete guess.

Finally, what is your purpose for making these Coroutines? For the sample code you’re showing there is no reason at all that a Coroutine is doing anything for you but causing overhead.

Part of the problem is that you are calling “yield return new waitforfixedupdate” every time the coroutine does its thing, what you really should do is declare a private waitforfixedupdate, and initialise it in awake, then yield return whatever you called that waitforfixedupdate(without the ‘new’) and it will produce less garbage.

So… (assuming C#)

private WaitForEndOfFrame waitFor;

void Awake() { 
waitFor = new WaitForFixedUpdate():
}

IEnumerator OnTriggerStay(Collider other)
 {
 currentAIState.OnTriggerStayState(other);
 yield return waitFor();
 }