Search Unity

Editor Hangs While Using UniRx/UniTask Alongside Addressables

Discussion in 'Addressables' started by bvance, Feb 14, 2020.

  1. bvance

    bvance

    Joined:
    Oct 25, 2012
    Posts:
    13
    Hey folks!

    Our project makes use of a library called UniRx (and its sister library UniTask) to do various kinds of asynchronous work. This week I discovered a way to make the editor hang indefinitely (by which I mean, I spent about 15 straight hours learning what I was inadvertently doing to achieve this, lol). It's pretty much the worst variety of hang: You can't click any editor menu buttons or command playmode to abort, but also the editor will never crash (I must end the task myself).

    I've prepared and filed a bug report to Unity, which uses the following toy example to manifest this behaviour:

    Code (CSharp):
    1. public class AddressableBreaker : MonoBehaviour
    2. {
    3.     async void Start()
    4.     {
    5.         var locator = await Addressables.InitializeAsync().Task.AsUniTask(); // only when we use 'AsUniTask' does the editor hang later! Without that bit it's fine
    6.         Debug.Log($"Finished first InitializeAsync! Resulting ILocator is null: {locator != null} t: {Time.unscaledTime}");
    7.        
    8.         var locatorAgain = await Addressables.InitializeAsync().Task;
    9.         Debug.Log($"Finished second InitializeAsync! Resulting ILocator is null: {locatorAgain != null} t: {Time.unscaledTime}");
    10.  
    11.         //await Task.Delay(100); // this line, if uncommented, prevents the hang from occuring...
    12.        
    13.         var tPrefab = Addressables.LoadAssetAsync<GameObject>("Prefab 1");
    14.  
    15.         Debug.Log("Still not hanging the editor yet! The editor should hang on the next instruction...");
    16.         var prefab = await tPrefab.Task;
    17.         Debug.Log($"Finished loading one prefab! Result is null: {prefab != null} t: {Time.unscaledTime}");
    18.        
    19.         Debug.Log($"Gonna just load a S***ton of things now as further stress testing...");
    20.         for (var i = 1; i <= 100; ++i)
    21.         {
    22.             var p = await Addressables.LoadAssetAsync<GameObject>($"Prefab {i}").Task;
    23.             Debug.Log($"Loaded prefab: {p} t: {Time.unscaledTime}");
    24.         }  
    25.        
    26.         for (var i = 1; i <= 100; ++i)
    27.         {
    28.             var o = await Addressables.LoadAssetAsync<ScriptableObject>($"Timeline {i}").Task;
    29.             Debug.Log($"Loaded timeline: {o} t: {Time.unscaledTime}");
    30.         }
    31.     }
    32. }
    The specific cause of failure seems to involve the following steps:
    1. Use the 'AsUniTask()' extension method to convert one of the Addressables system's Task objects into a struct of type 'UniTask' (basically what the library does is register a continuation of the System.Task whose function is to complete a simple Awaiter the library produces).
    2. Have your code 'await' the resultant UniTask.
    3. Having awaited the task, tell Addressables to load another asset
    4. Try to await the resultant AsyncOperation's System.Task
    5. Unity should now hang indefinitely!
    In our project we have prevented the issue simply by never converting an Addressables-provided System.Task into a UniTask!

    Now, of course I realize Unity is not responsible for all the 3rd party assets in the world and that it may not be the Unity team's job to investigate this bug! But since UniRx is fairly popular, I figured I'd file it + make this post (if only to help people avoid the thing I ran into). My sense of this problem is that UniTask is not doing anything particularly spicy or 'incorrect' with respect to how Addressables can be used; I do not believe it's trying to multi-thread or anything intense like that... so perhaps investigating this problem could reveal a range of subtle AsyncOperation-related issues on Unity's side?

    This toy example also does another weird thing I don't understand, which is: Calling "await Addressables.InitializeAsync().Task" seems to always return 'null' the first time, when it promises to return an instance of IResourceLocator?? Is that a known feature of the API, or a known bug or anything?
     
  2. TreyK-47

    TreyK-47

    Unity Technologies

    Joined:
    Oct 22, 2019
    Posts:
    1,822
    Sorry to hear you're having issues, but thank you for filing the bug report. Do you happen to have the ticket number for you bug report handy?