Ron Serruya
Ron Serruya

Reputation: 4426

How does "await" not block in Unity3d?

This is the code that I have

using System;
using System.Collections;
using System.Threading.Tasks;
using UnityEngine;

public class NewMonoBehaviour : MonoBehaviour
{
    // Start is called before the first frame update


    [SerializeField]
    GameObject player;
    void Start()
    {

    }

    // Update is called once per frame
    async void Update()
    {
        if (Input.GetKeyDown("space"))
        {
            Debug.Log("Start");
            await Task.Delay(3000);
            Debug.Log("End");
        }

        if (Input.GetKey(KeyCode.A))
        {
            player.transform.Translate(new Vector3(-1,0,0) * Time.deltaTime);
        }

        if (Input.GetKey(KeyCode.D))
        {
            player.transform.Translate(new Vector3(1,0,0) * Time.deltaTime);
        }
    }
}

When I press on space, I'm able to move left and right even when the delay is not over yet. In addition, I'm able to press on space repeatedly to get

Start
Start
Start
End
End
End

This works like I want to, but I'd like to understand why. I would imagine that everything within this method would be blocked until Task.Delay is done.

Upvotes: 2

Views: 2393

Answers (2)

kefren
kefren

Reputation: 1102

You made async the whole Update() method.

async void Update()
{//whatever needs to be done in a frame}

renders the Update method run asynchronously, so that Unity does not wait for it to return before going on. It goes on calling Update() on all other objects, doing its stuff, rendering the frame, until it reaches the same async void Update() on the next frame, on the same object. So, it can react to

if (Input.GetKey(KeyCode.A))
    {
        player.transform.Translate(new Vector3(-1,0,0) * Time.deltaTime);
    }

On the subsquent frame, even though the previous frame Update() is awaiting for await Task.Delay(3000). This is why you obtain the result you get.

BTW, async void Update() is IMHO a bad idea, because you get unexpected results when the various Update() methods return different values at unexpected times, and modify the variables at unexpected times. I would keep Update() synchronous, and eventually have it call an async method that does what you need.

Upvotes: 3

Richard Harrison
Richard Harrison

Reputation: 19393

To paraphrase MSDN: Asynchronous programming and uses the Task-based asynchronous pattern (TAP)

The .NET Task-based async model is exposed by the Task and Task types and the async and await keywords in C#

I realise that it isn't always easy to understand these documents; so basically what happens is that when you await in a method the return value is 'held' in the calling await Update(). Once the await has finished the caller will receive the value and this will cascade up the call tree.

The important thing is that each individual method invocation becomes asynchronous. The way I think of it as being rather like job cards you give to an employee. You can keep giving them new cards and each time they finish the job they give you back the card and you do what you have to do. The employee may choose to do the simple things first so you may well get the cards back in a different order but that doesn't matter.

Upvotes: 1

Related Questions