Async/Await is one of the most useful features in any programming language. In single threaded applications or applications like Unity where the UI runs on a single thread it is extremely useful for smooth functioning of the app to make Async calls which won’t block the main UI thread . We’ll get the whole code first so people who are frantically trying to solve the issues in their project can have a quick peek.
using UnityEngine;
using System.Threading.Tasks;public class TaskExample : MonoBehaviour
{
float \_elapsed = 0;
void Start()
{
Debug.Log("Start begins"); //Initialize a task completion source.
//This will be our source for creating a task and also holding the result on it's completion.
var tcs = new TaskCompletionSource<Vector3>();
Task.Run(async () =>
{
Debug.Log("Task started");
tcs.SetResult(await LongRunningTask());
Debug.Log("Task stopped");
});// ConfigureAwait must be true to get unity main thread context
tcs.Task.ConfigureAwait(true).GetAwaiter().OnCompleted(() =>
{
Debug.Log("Task completed");
transform.Rotate(tcs.Task.Result);
});Debug.Log("Start method ends");
}void Update()
{
if (\_elapsed > 1)
{
Debug.Log($"Update loop running for : " + Time.realtimeSinceStartup + " seconds");
\_elapsed = 0;
}
\_elapsed += Time.deltaTime;
}async Task<Vector3> LongRunningTask()
{
var rand = new System.Random();
var v = Vector3.zero;
// Do somethings that takes a long time
for (var i = 0; i < 30000000; i++)
{
v = new Vector3(rand.Next(0, 360), rand.Next(0, 360), rand.Next(0, 360));
}
return v;
}
}
Log :
The logs depict the flow of the code as it excutes the async tasks.
Async/await in C# is similar to promises in javascript to some extent. The underlying concept is the same.
You create a task and send it to say fetch some data from the server. Next you set a means for our code to store the result of the task whenever it comes back with a response from the server.
In the above example we create a TaskCompletionSource which will provide us with a source to create the task and also a source to hold the result on the completion of the task.
var tcs = new TaskCompletionSource<Vector3>();
Create the Task :
Task.Run(async () =>
{
Debug.Log("Task started");
tcs.SetResult(await LongRunningTask());
Debug.Log("Task stopped");
});
Using the result of the task on completion
// ConfigureAwait must be true to get unity main thread context
tcs.Task.ConfigureAwait(true).GetAwaiter().OnCompleted(() =>
{
Debug.Log("Task completed");
transform.Rotate(tcs.Task.Result);
});
Here the LongRunningTask( ) method returns a Vector3 which dictates the rotation for our gameobject to which this script is attached. The result of the LongRunningTask( ) method can be accessed by the Task.Result property which we set in
tcs.SetResult(await LongRunningTask());
Now we need to create a function called LongRunningTask() which will be async and will return a Vector3 which dictates the rotation for our gameobject to which this script is attached.
async Task<Vector3> LongRunningTask()
{
var rand = new System.Random();
var v = Vector3.zero;
// Do somethings that takes a long time
for (var i = 0; i < 30000000; i++)
{
v = new Vector3(rand.Next(0, 360), rand.Next(0, 360), rand.Next(0, 360));
}
return v;
}
Note : the return type is enclosed in Task<>. I made this mistake and spent a good 5 minutes wondering why I was getting an error.
Now in Unity Editor lets create a new scene and add a 3D Object of a capsule.
Create a capsule so we can see it rotate.
Now attach our script to this capsule and run! We can see the flow of the code in the logs and we can also see the capsule rotating in the scene.
Top comments (0)