Unity async / await: Coroutine's Hot Sister [C# & Unity]

preview_player
Показать описание
The C# async / await workflow can simplify your code and give you more granular control over your game in Unity.

Learn how to convert your current coroutine workflow, what a task is, how to run sequential and synchronous code and how to return data from an asynchronous function.

=========

0:00 Super professional intro
0:30 Standard coroutine workflow
1:19 Converting to async / await
2:44 Use-cases of async / await
3:10 Running functions sequentially
6:00 Waiting for synchronous tasks to complete
10:20 Mixing sequential and synchronous tasks
11:00 Returning data from an async function
14:20 Calling an async function from a non-async function
15:10 WebGL caveat
15:45 Other advanced async techniques
Рекомендации по теме
Комментарии
Автор

There are certainly other important caveats to mention with async.

You were constantly getting NREs in the background. This being caused by the fact that tasks do not respect Unity Object lifetimes.
Coroutines will stop when the object that started them is destroyed. Tasks will continue on regardless, and this means that they can continue outside of playmode, and through scene changes.
To counter this you need to use cancellation tokens, and they're somewhat difficult to grasp. In reality almost every task you start should really take a cancellation token.

Not only this, but there are situations you can get yourself into that completely silence exceptions occurring within a task-returning method. If you do not await a task it will not appropriately throw exceptions created within it. This can make bugs difficult to track down, and if you're not familiar with that fact it's a minefield.

vertxxyz
Автор

I think I ought to mention that most of the advantages listed here in favor of async/await are also present in Coroutines, but he doesn't write the Coroutine version in a way to take advantage of them.

For instance, when running Coroutines sequentially, you do not have to make a bunch of different functions and then a separate function to yield on each function sequentially. You can simply do what he does for the async function. You can have that function return IEnumerator (just like how he changes it to async) and run it using StartCoroutine. Then you simply yield return for each shape just like he does with the async version.
So in code it looks like this:

public IEnumerator BeginTest() {

for (var i = 0; i < _shapes.Length; i++) {
yield return _shapes[i].RotateForSeconds(1 + i);
}
}

Compare to the async version. It's identical.
Similarly, when talking about ways to wait for all the Coroutines to finish he doesn't even mention WaitUntil, or the fact that you can simply yield on Coroutines after starting them. The later method leads to code which is very similar to what he writes for the async function:

public IEnumerator BeginTest() {



Coroutine[] tasks = new Coroutine[_shapes.Length];
for (var i = 0; i < _shapes.Length; i++) {
tasks[i] = StartCoroutine( _shapes[i].RotateForSeconds(1 + i) );
}

foreach (Coroutine task in tasks)
yield return task;


}

Which again is almost identical to his async version.
The major advantage of async functions is the fact that you can return values from them like a Promise in Javascript. But Coroutines are native to Unity and are therefore better integrated into that system: for instance Coroutines line up with the frames of the engine as he mentions, async functions often continue even after you hit stop in the editor which he doesn't mention. Also, some default Unity methods (such as Start) can be converted directly into Coroutines simply by making them return IEnumerator.

APaleDot
Автор

Perfect use cases, great samples for comparison. Really makes you eager to use Tasks in your code. On point tutorial, good work!

kdeger
Автор

I think it's worth mentioning that async/await continues to work in the editor even after the game has stopped, unless you set an exit condition that takes this into account. Can lead to unexpected results, especially if moving, adding or removing scene objects, playing sound, etc. occurs inside asynchronous functions.

NexysStormcloud
Автор

Quick Tip.
don't use async void because because any exceptions can disappear into a black hole.

Try to get into the habit using async Task<returnType> so that you know what the result of the function was (whether it succeeded or failed etc)
if you want to be even more fancy you can also return a tuple wrapped in a task so you can return whether the function succeeded and also any other useful info if it failed, this will help when trying to debug the function so that you don't have to step through the entire thing.

I like to use this pattern:

async Task<bool success, string reason> DoSomething()

var result = await
if (result.success)
{
//Do another thing after success.
}
else
{
//Do something else after fail.
Log($"DoSomething() failed because: {reason}");
}

IvarDaigon
Автор

I don't like comparing content creators, as everyone has a unique approach. But you're basically the Brakeys 2.0 in the void of Brakeys. GIving us more indepth, higher level tutorials that is exactly what the space needs.

You definitely deserve much more Subscribers.

YulRun
Автор

Non-boring details from years of experience. I'm surprised of the way you've put all this information together in one video! Thank you!!!

humadi
Автор

Hey there, I just found your channel. I work full time as a C# backend dev and I always wondered how to apply all of these tools I use all the time like Tasks in Unity. I appreciate you doing these kinds of explanations nobody else on youtube is willing to do. Good work!

SwaggyProfessor
Автор

Oh... my... god. I've been self-taught for 42 years (since I was 7). I picked up C# about 17 years ago. I had NO IDEA you could do this. I have my own class for things that are timed. I never watched videos until I started with Unity and I'm learning SO MUCH even after all this time about programming in general. This is CRAZY POWERFUL and I bet every mid-level coder knows about it. I remember a few years back when I learned about reflection and params. That blew me away. I have had the ability to do basically what NetCode does for quite a while: have the server call a function on the client or visa versa.

path
Автор

I think this is the best Unity async/await tutorial I have ever seen. And I can swear I've seen pretty much of those.
It would be great to see more advanced stuff delving into async uses in Unity.

RichyAsecas
Автор

Nice one, would love to see a more advanced workflow, especially on how to deal with canceling tasks. The thing I still like about coroutines is that it kills itself when the game object is destroyed. With async/await (in my experience) it tends to get very complex with cancellation tokens and all of the try/catches everywhere.

igz
Автор

Almost spooky how well timed this is, having some trouble with Coroutine Sequentials and cancelling a Coroutine, so this is perfect!

Great explanation and well spoken, definite subscribe! :D

GenSpark
Автор

When I first learned about Coroutines it was ground breaking, the peak of technology for my silly indie brain.
Now I'm finding out about async/await/tasks and it's just wonderful. Truly amazing to see how there's always something new to learn.

francocougo
Автор

Too few developers who learn C# through just Unity understand that using IEnumerable for asynchronicity is not a typical thing in C# and that the purpose of the IEnumerable interface has literally _nothing_ to do with asynchronicity.

thinker
Автор

Nice work covering this subject and displaying the mulitple ways async/await can be used. Even a year+ on after the release of your video, its still a gold nugget!

vimalnaran
Автор

Everything you do, you do well! I am so excited to see your page gaining traction. It is well deserved

caleb
Автор

coming from a javascript background and being familiar with Promises (and having trouble wrapping my mind around coroutines) this video is a lifesaver! thank you so much

ckwallace
Автор

Definitely like the workflow of using Tasks instead of coroutines. You have much better control over it and it certainly makes waiting for things to complete a little easier.

ThShnizz
Автор

Found this video awhile ago, but I keep coming back because I forget the snytax or where in my code to implement the async or await functions.
Thank you so much for this video as it really helped me on my projects and will continue to help me on future Unity projects.

nicholassmith
Автор

Lovely. I come from a C# async/await web workflow and got into Coroutines when learning Unity. Am keen to refactor some of my code because of your video. Thanks!

dageddy