- Home /
yield return null vs yield return WaitForEndOfFrame
Hey guys, I wonder what is the difference between yield return null and yield return new WaitForEndOfFrame(). For example if i used this in a coroutine like that.
IEnumerator MyRoutine()
{
yield return new WaitForEndOfFrame();
Debug.Log("Hello");
}
IEnumerator MyRoutine2()
{
yield return null;
Debug.Log("Hi");
}
I think that it should produce the same result right ? Does anyone have an idea ?
Thanks a lot !
Answer by rutter · Jul 23, 2014 at 10:43 PM
They're very similar, but return at different points in the frame.
Unity performs many operations once per frame, including:
Input processing
Main update (including
Update()
)Main coroutine updates (including
yield return null
)Late update (including
LateUpdate()
)Scene rendering (quite a few steps)
Gizmo/UI rendering
End of frame (including
WaitForEndOfFrame
)
One returns just before rendering, the other returns just after (but just before the frame is displayed). When the difference isn't important, I usually use and recommend yield return null
, as it's closer to the way other Update
and coroutine functions work.
This is explained in more detail at the execution order manual page. Recently, they've added a handy chart:
Does anyone have any idea on memory management about this issue?
yield return null; seems to be a simple command while yield return null WaitForEndOfFrame as the new keyword and WaitForEndOfFrame is an actual class
So I would suspect it to create an object like a subsidiary coroutine to the existing coroutine. Is that so?
@fafase:
WaitForEndOfFrame is, like you said, just a class. Actually it's an empty class. It's declared as:
public sealed class WaitForEndOfFrame : YieldInstruction
{
}
YieldInstruction is also just an empty class (they could have used an interface for that):
public class YieldInstruction
{
}
So the only thing the coroutine scheduler actually use from that class is the type of the object. Of course every class instance need at least 1 byte of memory that can be addressed. Usually with a 4 byte alignment an instance uses 4 bytes. However i haven't tested it yet. Could be more and could be different depending on the target platform.
edit It seems to be 8 bytes according to this SO answer
WaitForSeconds is also just an ordinary class, but it holds additional information for the scheduler:
public sealed class WaitForSeconds : YieldInstruction
{
internal float m_Seconds;
public WaitForSeconds(float seconds)
{
this.m_Seconds = seconds;
}
}
The internal value is used by the scheduler to deter$$anonymous$$e when it has to schedule this coroutine again.
So since WaitForEndOfFrame as well as WaitForFixedUpdate are just empty classes it should probably be no problem to actually cache a single instance of that class and pass that one to yield return whenever you need it.
A helper class like this might work:
public static class Wait
{
private static WaitForEndOfFrame m_WaitForEndOfFrame = new WaitForEndOfFrame();
private static WaitForFixedUpdate m_WaitForFixedUpdate = new WaitForFixedUpdate();
public static WaitForEndOfFrame ForEndOfFrame
{
get {return m_WaitForEndOfFrame;}
}
public static WaitForFixedUpdate ForFixedUpdate
{
get {return m_WaitForFixedUpdate;}
}
}
Use it like this:
IEnumerator SomeCoroutine()
{
// SomeStuff
yield return Wait.ForEndOfFrame;
// Some more stuff
}
This would prevent the creation of a new instance each time you need one of those classes. It's of course possible that Unity has some additional overhead in the scheduler itself. But we can't do anything about that ^^.
Answer by Bunny83 · Jul 23, 2014 at 10:46 PM
Of course both of your examples will execute the Debug.Log line, however at different times. If you yield "null" (or any other value that isn't recognised) Unity will schedule this coroutine the next frame right after Update is called. When you use WaitForEndOfFrame, The coroutine will be scheduled this frame once all cameras are rendered and the GUI is drawn. It will run right before the buffers are swapped and the frame is finished.
See this great Unity Gems article for more information
too bad, the website seems to be down by now, I only managed to access it with an Archive : https://web.archive.org/web/20140626101041/http://unitygems.com/
Looks like the site has a new domain name, the article is now at https://unitygem.wordpress.com/coroutines/
Answer by unity_123uzunince123 · Nov 11, 2020 at 09:24 PM
This article is a bit old, maybe at that times the system worked different. But I've made an experiment resulting different from you have talked. here is the code:
using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
public class CizgiCizKaydet : EventTrigger
{
public static bool allow = false;
public override void OnEndDrag(PointerEventData eventData)
{
StartCoroutine(AllowPrintForOneFrame());
}
IEnumerator AllowPrintForOneFrame()
{
allow = true;
yield return new WaitForEndOfFrame();
// yield return null;
allow = false;
}
private void Update()
{
if (allow )
print("Merhaba");
}
}
for the "yield return null;" version the print("Merhaba"); is executed twice. for the "yield return new WaitForEndOfFrame();" version print("Merhaba"); is executed once.
I've the same problem and asked it on stackoverflow, nobody seems to have any answer for that https://stackoverflow.com/questions/64942789/waitforendofframe-is-called-twice-at-first-run
This is most likely not the same issue. As derHugo has explained on your SO question, the very first frame in Unity has several edge cases. That's also true for the value of deltaTime and a few other things. So you should not rely on that.
And no, your second debug log is not some how called twice. You just have two coroutines waiting for the "end of frame" which somehow does not happen at the very first frame. So your first coroutine simply completes together with your second one at the end of frame 2. That's exactly what you're seeing. As others have suggested, pass the frame count as a parameter to your coroutine so it actually stays the same, even though the coroutine lasts longer than one frame. Then you will see that one of the two "4" debug logs comes from frame 1 and the other from frame 2. Time.frameCount returns the frame at the point it's called. Since both coroutines finish at frame 2, of course both show a frameCount of 2. However that's not the frame it was actually started.
In this case here he actually reacts to the "OnEndDrag" event. So this does not happen at the first frame. The most likely reason why he sees the message two times is because he probably has attached the script to two gameobjects. Since his "allow" variable is static it will of course affect both scripts, even though only one of them may receive the event.
Answer by NogeGames · May 17 at 08:27 AM
The best answer is wrong.
When you yield return WaitForEndOfFrame the coroutine will be resumed at the end of the current frame, after scene and ui rendering.
When you yield return null the coroutine will be resumed in the next frame right after the Update is completed.
WaitForEndOfFrame is useful when you want the coroutine to be resumed later this frame, while returning null will resume it after next frame's Update, which is a very important difference sometimes.