I just downloaded the new Unity 2017 to test out new C# version, was messing around with Tasks/async/await and I guess I found a way to break the editor and make it unresponsive when trying to run scene.
Try at your own risk, you’ll probably need to close the process using task manager, so be sure to save all your work before this.
public class TestClass : MonoBehaviour {
void Awake(){
Test ().Wait();
}
private async Task Test(){
await Task.Delay (new System.TimeSpan (0, 0, 5));
Debug.Log ("Done awaiting...");
}
}
I if you remove the .Wait() part it’ll work without problems, however .Wait() seems to be causing editor to stuck when trying to run.
What I expected the above code to do is to wait for 5 seconds then continue running (so it’s like adding extra delay during application startup)
I can’t really find proper explanation to it, the only thing I could come up with is that unity running in a single thread and scheduled the Test() task to be run after Awake() is finished (or at whatever later time) but Awake needs to wait for Test… creating something like dead lock, Awake waiting for Test to finish and Test waiting for Awake to start…
P.S: I wasn’t trying to achieve anything using that method, and I know it’s not a good practice to do it that way, but it’s something I came across while messing around.
Also, don’t bother waiting for it to fix it self, if it doesn’t work after 1 minute then probably won’t work at all, been 30 minutes already and editor won’t even let me exit.
I guess you found out by now, however for those still stumbling upon this thread, when doing this:
Task.Run(async ()=>
{
await Task.Delay(5000);
}).Wait();
You are essentially telling the main thread to wait for the tasks completion. Now this is a task that will take 5 seconds (delay for 5000ms) - thus blocking the main thread for that amount of time.
Thus you could also write this:
Thread.Sleep(5000);
Which would make no difference and also suspend the main thread - causing the editor to hang. This happens because the whole unity editor runs on the main thread (UI Thread) thus it hangs for 5 seconds.
When you want to do somthing after a Task is finished you have multiple possibilities.
TPL way:
Task.Run(async ()=>
{
await Task.Delay(5000);
}).ContinueWith(t=>DoSomething());
This schedules another task after the previous task has finished - Note however that you probably want to add multiple continuations depending on the tasks result (e.g. one continuation for the exception case, one for the standard case)
Async/Await
async Task Awake()
{
Debug.Log("Do something at the beginning");
await Task.Delay(1000); // wait asynchronously
Debug.Log("After 1000ms");
await Task.Run...
}
In this case you state that the Awake function is an async Task (don’t use async void! or else Exceptions will get swallowed) which is supported by Unity. Than you can use await to wait for tasks (such as Task.Delay) - which is an asynchronous waiting mechanism - thus it does not block the main thread, but rather returns to the caller of the method. You can imagine it like a coroutine in Unity or a yield return statement in C#. Thus at every await the execution of the method is “suspendend” and Unity can continue to call other Awake / Update methods etc.
You should probably work through a lot of tutorials (and probably understand Coroutines / Yield Return statements beforehand). Even though async/await looks simple, there is a lot going on under the hood that you should be aware of, or else you will face bugs that you cannot solve / explain.
Hope this helps someone 