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

Question Issue with Await Blocking RuntimeInitializeOnLoadMethod

Discussion in 'Scripting' started by TCYeh, Jul 18, 2023.

  1. TCYeh

    TCYeh

    Joined:
    Jul 25, 2022
    Posts:
    51
    Hello,

    I'm currently testing the usage of the RuntimeInitializeOnLoadMethod attribute with asynchronous methods in Unity. However, it seems that using the await keyword does not block Unity from calling the next function in the lifecycle order.

    Here is a sample of my testing code:
    Code (CSharp):
    1. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]
    2. static async void OnBeforeSplashScreen()
    3. {
    4.     Debug.LogError($"[BeforeSplashScreen1] [{DateTime.Now}] [{Time.realtimeSinceStartup}] Before SplashScreen is shown and before the first scene is loaded.");
    5.     await Task.Delay(5000);
    6.     Debug.LogError($"[BeforeSplashScreen2] [{DateTime.Now}] [{Time.realtimeSinceStartup}] Before SplashScreen is shown and before the first scene is loaded.");
    7. }
    8.  
    9. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    10.     static void OnBeforeSceneLoad()
    11. {
    12.     Debug.LogError($"[BeforeSceneLoad] [{DateTime.Now}] [{Time.realtimeSinceStartup}] First scene loading: Before Awake is called.");
    13. }
    14.  
    15. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
    16. static void OnAfterSceneLoad()
    17. {
    18.     Debug.LogError($"[AfterSceneLoad] [{DateTime.Now}] [{Time.realtimeSinceStartup}] First scene loaded1: After Awake is called.");
    19. }
    20.  
    21. [RuntimeInitializeOnLoadMethod]
    22. static void OnRuntimeInitialized()
    23. {
    24.     Debug.LogError($"[RuntimeInitializeOnLoadMethod] [{DateTime.Now}] [{Time.realtimeSinceStartup}] First scene loaded2: After Awake is called.");
    25. }
    26.  
    27. void Awake()
    28. {
    29.     Debug.LogError($"[Awake] [{DateTime.Now}] [{Time.realtimeSinceStartup}]");
    30. }
    31.  
    32. void OnEnable()
    33. {
    34.     Debug.LogError($"[OnEnable] [{DateTime.Now}] [{Time.realtimeSinceStartup}]");
    35. }
    36.  
    37. void Start()
    38. {
    39.     Debug.LogError($"[Start] [{DateTime.Now}] [{Time.realtimeSinceStartup}]");
    40. }
    41.  
    42. int frame = 0;
    43. void Update()
    44. {
    45.     if (frame < 1)
    46.     {
    47.         Debug.LogError($"[Update] [{DateTime.Now}] [{Time.realtimeSinceStartup}]");
    48.         frame++;
    49.      }
    50. }
    And this is the result:
    asyncTest.png
    Based on the code execution, you can observe that instead of waiting for the completion of "BeforeSplashScreen1", "BeforeSplashScreen2" is called at the end of the process. However, when I attempted to use a while loop on the main thread to block it, the blocking was successful.

    If there is a solution to block the lifecycle execution using an asynchronous method properly?
    Thank you in advance.
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    Yes, the point of async code is to be non-blocking.

    Consider
    async void
    methods to be fire-and-forget methods. They run in the background until they're done. They won't hold up the application.

    You can either use non-async code, or introduce your own system for executing things in a particular order.
     
    Bunny83 likes this.
  3. TCYeh

    TCYeh

    Joined:
    Jul 25, 2022
    Posts:
    51
    Thank you for your response.

    In my case, I am specifically testing this behavior for Addressables. My intention is to preload assets at the BeforeSplashScreen stage, which requires the use of async code.

    When you mentioned "introduce your own system for executing things in a particular order," I am curious to know how I can accomplish that. Could you please provide some guidance on implementing such a system?
     
    Last edited: Jul 18, 2023
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,769
    You should just load what you need synchronously with the
    AysncOperationHandle.WaitForCompletion()
    method.
     
  5. CodeRonnie

    CodeRonnie

    Joined:
    Oct 2, 2015
    Posts:
    280
    You can't block at BeforeSplashScreen with async methods, unless you do it manually like spinning in an infinite while loop until all of your Addressables load. I would not do that. Hanging the application like that right off the bat with no visible loading indicator could be the reason your game is rejected from certain hardware platforms. I would have an initial scene that loads first, in order to load all of the addressable assets you need to preload. In that loading scene you can display progress, have something moving on screen so users know the application isn't totally frozen, and when all assets have been loaded, or checked that they have been downloaded and cached in the case of remote asset bundles, whatever the specifics, then you can load the next scene.
     
    spiney199 likes this.