Search Unity

WaitUntil() or While() in coroutine

Discussion in 'Scripting' started by Kalita2127, Aug 14, 2019.

  1. Kalita2127

    Kalita2127

    Joined:
    Dec 6, 2014
    Posts:
    279
    Hi I have a simple question. What's the different between
    WaitUntil(condition)
    and
    while(condition)
    ?
    In my real case I want to wait until
    Caching 
    is ready. So I'm just curious which one is better between those two? Thank you.
     
  2. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    I assume you mean the difference between:

    Code (csharp):
    1. yield return WaitUntil(() => condition);
    and
    Code (csharp):
    1. while(!condition)
    2.     yield return null;
    ?

    Because in that case they're equivalent, except that the first one allocates memory for the lambda.

    .. Also it might be that the first one always waits at least one frame, I'm unsure at the moment.
     
  3. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    Code (CSharp):
    1. yield return new WaitUntil(condition);
    is just a shortcut for

    Code (CSharp):
    1. while(!condition) yield return null;
    It makes no sense what to chose in general.
     
  4. Kalita2127

    Kalita2127

    Joined:
    Dec 6, 2014
    Posts:
    279
    I see, so they are just the same but the first one is a little bit heavy right? Thank you!
     
  5. batvink

    batvink

    Joined:
    Sep 26, 2019
    Posts:
    61
    WaitUntil clearly checks the condition every cycle.
    Is there any advantage in using WaitForSeconds in the yield (e.g 0.1 seconds) if you know it could take a while to complete?
    Will this reduce the load, or is it still using as much compute power to wait?
     
  6. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    Style-wise,
    WaitUntil
    is an extra thing added by Unity, whereas
    while(...) yield return null;
    is standard C#. So the usual things apply: if you want to be more Unity-ish, use WaitUntil, if you want readability fom strangers, use while. If you're teaching a practical "type X to do Y" lesson, use WaitUntil. If you're teaching programming, use while.
     
    Lorrak and Kurt-Dekker like this.
  7. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    They're probably doing the check for time behind the scenes every frame anyway, so it'll only be relevant if the WaitUntil check is expensive.
     
    Lorrak likes this.
  8. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    I've assumed every WaitForSeconds is stored in a single sorted list which is checked 1nce/frame, For example, 5 coroutines are waiting on times: [34, 35, 36, 36, 36] and the system only checks "is it time 34 yet"? If someone waits 1 second at time 33.5, we add it as 34.5. Basically a Priority Queue.

    But I've never looked. And the only gain wold be if you have many coroutines waiting for several frames, and it's not much.
     
    Bunny83 likes this.
  9. angusbjones

    angusbjones

    Joined:
    Nov 24, 2012
    Posts:
    8
    Just for anyone else coming across this:
    The two expressions do differ in execution as the first expression (yield return WaitUntil) WILL wait at least one frame even if the condition is true on return.
    This bit me within the following code:
    Code (CSharp):
    1. yield return new WaitUntil(() => _analytics.RequiresUpdate());
    2. _analytics.Update();
    Update() would throw an Assert as RequiresUpdate() returned false because between the condition being checked (in the first frame) and the yield actually continuing (on the next frame), RequiresUpdate() would change from returning true to false. I'll repeat it just so it's obvious but this delay of one frame will only happen between the condition returning true and the 2nd line proceeding if the condition returned true on the first frame the yield is returned. After the first frame, if the condition returns true then the 2nd line is continued on the same frame.
    Code (CSharp):
    1. while (!_analytics.RequiresUpdate())
    2.     yield return null;
    3. _analytics.Update();
    is how I rewrote the above code to ensure Update() (barring race conditions) is only called when RequiresUpdate() is in fact true.

    I've no complaints about this behaviour as there are definitely scenarios where I want to know a frame has fully completed prior to execution continuing in a coroutine though it might be nice for it to be explicitly noted in the documentation.
     
  10. Jeshira

    Jeshira

    Joined:
    Aug 3, 2017
    Posts:
    12
    Late comment about this, but I wanted to add my two cents since that's the topic I fell on looking for this.

    Where it might seriously make a difference is in the conditions. As others pointed out WaitUntil uses "yield return null" and that does not have a fixed time "when" the condition is tested again. If your condition is never met, you end up in a endless loop, so you would probably like to add a counter (tries or time) which might be an issue with using WaitUntil. You could have a condition break "as long startTime + delay > currentTime" but it's over-engineering WaitForSeconds for sake of using WaitUntil.

    For example, localisation service. You need to wait for GPS to initialize, but what garantee do you have that it would come out of this status. If you go with tries, it may run out, in a second or 5, before initialization is done with WaitUntil. Unity example of LocalisationService uses 20 secs with a looped through yield return WaitForSeconds(1), decrease int maxWait, and exit loop when init ends or seconds expire.

    Basically, you can use WaitUntil if you have a garantee that condition will be met and time frame is not an issue. Otherwise, you best not use it so you can control the endless loop safeguards.
     
  11. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,005
    While I do agree that WaitUntil is kinda pointless, what exactly do you mean with that? You can include the same considions you can include in a while loop that does a yield return null. For example:

    Code (CSharp):
    1. float timeout = 5f;
    2. yield return new WaitUntil(()=>condition || (timeout -=Time.deltaTime) <= 0);
    I don't want to suggest using this. WaitUntil allocates memory as it's an object and the closure also requires some memory. Though you could do the same things that way. Abusing WaitUntil like that of course is not recommended. First of all you allocate extra memory. The other issue is that inline-lambda / closure expressions can get really long and hard to read. If you need a WaitUntil with a timeout more often, it may make sense to create an actual custom yield instruction which does just that. Something like a
    WaitForSecondsOr(5f, ()=>condition)
     
    Jeshira and Owen-Reynolds like this.
  12. anthonygh2002

    anthonygh2002

    Joined:
    Nov 3, 2020
    Posts:
    1
    for some reason, using the same condition in while and waitUntil didn't give the same result.

    yield return new WaitUntil(()=>!InAtmosphere(planetToFollow.transform.localScale.x+150.0f)); didn't wait properly, the character started to lag in movement (the character moves according after the waituntil finishes and stops in a certain condition).

    while(!InAtmosphere(planetToFollow.transform.localScale.x+150.0f))
    yield return null;
    was actually much better!

    i still don't know the exact difference between them, but there's definitely one
     
  13. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,005
    Uhm, you do realise that the condition would need to be inverted? Right?. "waitUntil", as the name suggests, waits until the condition is true. On the other hand a while loop will loop "while" the condition is true. So waitUntil requires the condition to be false in order to wait and will terminate when the condition is true. A while loop requires the condition to be true in order to wait and will terminate when the condition becomes false.
     
  14. Jeshira

    Jeshira

    Joined:
    Aug 3, 2017
    Posts:
    12
    I simply meant you might not want to systematically test condition every frame, it's useless and a bit intensive.
     
  15. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,203
    Nothing about that should be intensive.
     
    Last edited: May 10, 2023
    Kurt-Dekker likes this.
  16. CandyQAZ

    CandyQAZ

    Joined:
    Nov 25, 2022
    Posts:
    1
    Also, to wait to the end of frame, if you want this, you can use WaitForEndOfFrame