Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

C# Coroutine WaitForSeconds Garbage Collection tip

Discussion in 'Scripting' started by WarpB, Jan 27, 2014.

  1. ttesla

    ttesla

    Joined:
    Feb 23, 2015
    Posts:
    16
    Code (CSharp):
    1.  bool IEqualityComparer<float>.Equals (float x, float y) {
    2.                 return x == y;
    3.             }
    @Tochas I guess we shouldn't compare float values with "==" operator.
     
  2. phobos2077

    phobos2077

    Joined:
    Feb 10, 2018
    Posts:
    350
    My simple solution for case when I can't always use the same instance of WaitForSeconds because delay is random:

    Code (CSharp):
    1. public class WaitForSecondsMutable : CustomYieldInstruction
    2. {
    3.     private float waitUntil;
    4.  
    5.     public WaitForSecondsMutable()
    6.     {
    7.     }
    8.  
    9.     public WaitForSecondsMutable(float seconds)
    10.     {
    11.         waitUntil = Time.time + seconds;
    12.     }
    13.  
    14.     public WaitForSecondsMutable Wait(float seconds)
    15.     {
    16.         waitUntil = Time.time + seconds;
    17.         return this;
    18.     }
    19.  
    20.     public override bool keepWaiting => Time.time < waitUntil;
    21. }
    Usage is simple, just have one instance of this class per concurrent Coroutine and instead of:
    Code (CSharp):
    1. yield return new WaitForSeconds(delay);
    You write:
    Code (CSharp):
    1. yield return waiter.Wait(delay);
    Zero allocations per Wait call.
     
    khaled24 and Biggerandreas like this.
  3. yyylny

    yyylny

    Joined:
    Sep 19, 2015
    Posts:
    92
    That's a good idea but it won't work with concurrency. If you call waiter.Wait() for a second time before the first waiter.Wait() has returned it will restart the timer and both Wait() methods will return at the same time. For example:

    Code (CSharp):
    1.  IEnumerator Start()
    2.     {
    3.         StartCoroutine(Test());
    4.         yield return new WaitForSeconds(2);
    5.         StartCoroutine(Test());
    6.     }
    7.  
    8.     IEnumerator Test()
    9.     {
    10.         yield return waiter.Wait(5);
    11.         Debug.Log("Test");
    12.     }
    Instead of printing "Test" after 5 and 7 seconds it will print "Test" twice after 7 seconds. I could use another instance of WaitForSecondsMutable but it defeats the purpose of using less allocations.
     
    phobos2077 likes this.
  4. friuns3

    friuns3

    Joined:
    Oct 30, 2009
    Posts:
    307
    Code (CSharp):
    1. //some magic with Templates to avoid allocations
    2. //yield return Temp.WaitForSeconds(1);
    3. //yield return Temp.WaitForSecondsRealtime(1);
    4.  
    5. public partial class Temp
    6. {
    7.     public static WaitForSecondsRealtime WaitForSecondsRealtime(float interval)
    8.     {
    9.         return Cache(arg => new WaitForSecondsRealtime(arg), interval);
    10.     }
    11.     public static WaitForSeconds WaitForSeconds(float interval)
    12.     {
    13.         return Cache(arg => new WaitForSeconds(arg), interval);
    14.     }
    15.    
    16.     public static T Cache<T, T2>(Func<T2, T> func, T2 key)
    17.     {
    18.         if (Temp<Dictionary<T2, T>>.value.TryGetValue(key, out T t))
    19.             return t;
    20.         return Temp<Dictionary<T2, T>>.value[key] = func(key);
    21.     }
    22. }
    23.  
    24. public static class Temp<T> where T : new()
    25. {
    26.     public static readonly T value = new T();
    27. }  
    28.  
     
  5. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,722
    Isn't this potentially cueing yourself up for a memory leak if you use the Get method here in a dynamic way (rather than hardcoded time intervals)?
     
    phobos2077 likes this.
  6. Deuchie

    Deuchie

    Joined:
    Jan 28, 2021
    Posts:
    1
    No, at least not for me. I am new to Unity but not new to coding. Unity does coding in a special way, making me uncertain of almost everything I come up with. Now I am even searching for basic things just for sure.

    Everywhere I went I found that the coroutine examples used `yield return new` so I wondered if caching the object would be a bad idea, e.g. altering states inside (I've lost trust in almost anything since I found that I should not use != null on Unity Objects). That's why I came searching.