I’m using Addressables on a WebGL title, and am otherwise successfully using managed Tasks for the whole game.
However, I have stumbled on a issue, that awaiting the tasks returned by IAsyncOperation.Task, yields an error:
Unrelated, but the correct spelling is “acquire”
I am a curious person, so I dived into the source code for the Addressables package, and stumbled onto the Task property’s getter implementation in AsyncOperationBase. What it currently does is create a Task with the System.Threading.Tasks.Task.Factory.StartNew method, which delegates the provided callback to a shared thread pool. That callback simply blocks on the internal WaitHandle, then returns the result.
I am not privy to all implementation details of the Addressables system, but from reading that method, there is no point for having this multithreading requirement, as one could use the Completed/Destroyed events together with a TaskCompletionSource instead, which would allow all of this to happen in a single thread.
In fact, I have implemented this for my own use as an extension method and it works, but I think that Unity would benefit on having this implementation for the whole userbase. Below is the snippet:
public static Task<T> Task<T>(this AsyncOperationHandle<T> self)
{
var source = new TaskCompletionSource<T>();
void Cleanup()
{
self.Completed -= OnCompleted;
self.Destroyed -= OnDestroyed;
}
void OnCompleted(AsyncOperationHandle<T> handle)
{
Cleanup();
switch (handle.Status)
{
case AsyncOperationStatus.Failed:
source.SetException(handle.OperationException);
break;
case AsyncOperationStatus.Succeeded:
source.SetResult(handle.Result);
break;
}
}
void OnDestroyed(AsyncOperationHandle handle)
{
Cleanup();
source.SetCanceled();
}
self.Completed += OnCompleted;
self.Destroyed += OnDestroyed;
return source.Task;
}