differences between async/await c# and coroutines unity3d

I would like to know deeply differences between async/await c# and coroutines unity3d
I know how coroutines work. They are not async and only are executed inside one thread and concecutively (event loop) like execution of updates,fixedupdates,…
If it reaches to a yield line, returns from it and executes other scripts and comes back again in the next frame(yield return null) or after waiting n secs

You pretty much understand coroutines. To understand C# async, hie thee to your favorite C# .NET repository on threading and learn whatever you can there.

Keep in mind you cannot use ANY of the Unity API from another thread, so if you want to play with threading, you may also need a marshaling layer to get your results or delegates back into the main Unity thread before they can be meaningfully used.

1 Like

Async/await is a whole framework that lets you do all sorts of different asynchronous operations. A lot of people make the mistake of thinking async is only for threads. It’s not, you can get them to work like Coroutines if you want:

  1. Don’t use Task.Run(). That launches your async method in a new thread. You can’t run Unity-specific code in a separate thread.
  2. Most of the time you want async methods to return Task. The “T” is a return value, which is something you don’t have with a coroutine. So you can have a Task method that is like a coroutine but returns an int value. The Task object itself is similar to the Coroutine object; you can use it to stop/query the method while it’s running.
  3. One exception to rule 2 is that you will want the initial call of an async method to be async void instead of async Task. The async void method is like calling StartCoroutine() from a normal method. You can make a wrapper method that works like StartCoroutine.
  4. Use “await Task.Delay(1000)” instead of “yield return new WaitForSeconds(1)” and “await Task.Delay(1)” instead of “yield return null”.

So to change a coroutine to async:

void NormalMethod() {
    StartCoroutine(MyCoroutine());
}

IEnumerator MyCoroutine() {
  DoStuff();
  yield return new WaitForSeconds(2f);
  DoOtherStuff();
}
void NormalMethod() {
  StartTask(MyAsync());
}

//This is a helper method, you could make a static one that you use everywhere
async void StartTask(Task task) {
  await task;
}

async Task MyAsync() {
  DoStuff();
  await Task.Delay(2000);
  DoOtherStuff();
}
3 Likes

Async/await does not necessarily run asynchronously in terms of threading / parallelism. It always depends on the usage, the synchroniuation context and last but not least the implementation itself.

The primary idea is to stop execution within a method to wait for another task while keeping other stuff - especially UIs - responsive and resume to that point (continuation) once the task has finished.
Methods can then be written in a similar fashion to coroutines and it’s often easier to understand the program’s flow - in many cases at least.

There are already threads in this forums that cover this (and specifically usage in Unity) quite nicely. Some threads do also provide different attempts to combine and/or adapt coroutine-functionality with async/await.

1 Like

I would remove the StartTask method and mark the NormalMethod async instead. It doesn’t change anything on the normal method, yet allows to await something within that method directly.

yes it is completely true. If we want to use unity3d API inside another thread (unity uses another thread other than main thread for .NET dlls,…), we get an error and so we have to apply events queue or call back functions and coroutines
But we can use .net4.5 experimental inside unity2017 and call async functions correctly without any problem (all of them are inside the main thread)

Don’t use Task.Run().
are you sure it creates threads in native C# applications? In other words, If you write Task.Run() 10 times, you will have 10 threads? somebody says async/await are single thread purely unless async functions use extra threads to do procedures.
yes in unity3d it is a problem.

So you say Async/await is more general/generic and can be coroutines too (similar procedure) and also can be single or multi thread

Well, “NormalMethod” was supposed to be an example of a non-async method, and how to call an async method from one, the way you call a Coroutine from a non-Coroutine. But yeah you can make everything async just like you could make everything a Coroutine if you wanted.

Generally, yes, Task.Run will create a new thread in the thread pool. I guess the compiler MIGHT be able to run the async method synchronously if you don’t have any await’s anywhere in there, but if you don’t have any await’s then there’s not much point in making a method async.

Yes. Generally, Task.Run will launch it in a new thread, while just calling an async void method directly will launch it in the same thread.

I’m aware of that, but it’s just something that necessarily happens at some point anyway. :slight_smile: I’d not hide it somewhere unless you really wanna go fire and forget - and that’s usually against async/await.

I read a lot of topics/blogs/etc about that and confused
"Task.Run creates a new thread definitely, it is not true"some people say it depends and there is a concept “synchronization context and ConfigureAwait”, some experiments showed that it depends on the application environment.
for example if your application is inside console, it is different from win form…