Best practices: Async vs. coroutines - Unite Copenhagen

Поділитися
Вставка
  • Опубліковано 4 лис 2024

КОМЕНТАРІ • 62

  • @jeangodecoster
    @jeangodecoster 5 років тому +76

    My #1 point for using Async is that you can use it inside scriptable objects and standard C# classes

    • @chromezephyr8959
      @chromezephyr8959 Рік тому +1

      This. Scriptables that have functionalities inside must use async.

  • @manituan4956
    @manituan4956 5 років тому +61

    It's common practice to rename async methods by adding the suffix "Async".
    Utils.LoadScene -> Utils.LoadSceneAsync
    Good talk!

    • @GamesForTheWlN
      @GamesForTheWlN Місяць тому

      Too bad this convention is impossible to reinforce for Unity events considering they won't receive the event message if they're called `StartAsync`, `AwakeAsync`, etc.

  • @masonwheeler6536
    @masonwheeler6536 4 роки тому +83

    27:16: "Finally, coroutines are familiar to most Unity developers. Async isn't."
    Counterpoint: Async is familiar to most C# developers starting out with Unity, but show them coroutines and they're like "what in the world is this crap?!? Why not just use async?"

    • @joncross5166
      @joncross5166 4 роки тому +3

      This was me a few days ago!

    • @normalhumanbeing6066
      @normalhumanbeing6066 3 роки тому +2

      this is exactly what i was thinking!!!

    • @peteruelimaa4973
      @peteruelimaa4973 3 роки тому +1

      Jep!

    • @restushlogic5794
      @restushlogic5794 3 роки тому +1

      Lol me.

    • @__dane__
      @__dane__ 3 роки тому +4

      There’s definitely more documentation/tutorials/information out there about coroutines for Unity then there is for using async with Unity

  • @mandisaw
    @mandisaw 5 років тому +7

    Coming from a Java background, multithreading/asynchronous coding in C#/Unity has been one of the biggest challenges to wrap my head around. I've gotten really used to Futures, with custom-configured ExecutorServices to handle thread management and UI syncing/callbacks. But async/await (and its kissing-cousin, Promises) definitely provide an easier mental transition - if you can keep straight what can happen in a worker/non-main context and don't mind relinquishing control over where/how your code will ultimately run*. I still feel hobbled, but at least I can move around a little bit faster :)
    * There was a GDC '17 AI summit talk with a technical deep-dive into managing core-usage while using asynchronous code that folks should check out - Beyond Framerate: Taming Your Timeslice Through Asynchrony

  • @slowdragon4169
    @slowdragon4169 4 роки тому +26

    whenever im having trouble sleeping i jsut turn up this talk. its so damn good

  • @IbakonFerba
    @IbakonFerba 5 років тому +10

    Using this for UI solves so many problems!

  • @FranciscoTChavez
    @FranciscoTChavez 5 років тому +11

    When async was put into Unity, I didn't have much use for it because I already knew more than one way to create a background thread. For me, the big issue with background threads is that I don't always know what will and won't run from a background thread in Unity. For instance, the error logging that he mentioned in the "Exception Hiding" Section of his talk; that's one of the things that doesn't work in background threads. Unity has a lot of things that doesn't work in background threads; it's an issue I've come across quite a bit when coding in Unity. Even calling the ToString() method on an Exception from an background thread will give you a warning because that can throw an Exception on certain Unity API items when called from a background thread. One of the hopes I have for DOTS, is that it might enable things that didn't work background threads (before now) to run in background threads in the near future.
    Coroutines run on the main thread, therefore, they have greater access to the Unity API. You can run things in a coroutine that can't run in async because the coroutine runs on the main thread. For instance, if you are doing a lot of interactions with the Graphics class or running Compute Shaders, you will be stuck in the main thread.
    I'm not trying to say that async is bad. It's a nice, short, and quick way to create a piece of code that runs in a background thread that returns a result without blocking the parent thread (which may or may not be the main thread). While coroutines are great for breaking up a long running (or multi-state) process that can't leave the main thread. Shoot, I've even launched plenty of non-blocking, background threads from coroutines, just so that I can offload work from the main thread while maintaining current state in long running processes. Both items have their uses.

    • @r1pfake521
      @r1pfake521 5 років тому +16

      I think you miss some information about about the way async works, first of all async uses tasks, not threads. Yes most tasks will run on background threads, but not all (just google tasks vs threads if you want to know more details about the difference). Next the tasks don't have to run on a background thread, the async "callbacks" use the SynchronizationContext. The "default" SynchronizationContext will (in most cases) run the async tasks on a background thread. But like you said a background thread can't access the Unity API, that's why Unity has a custom SynchronizationContext which synchronizes all async "callbacks" back to the main thread. So you can access the Unity API with async mehods. If you want to use async methods which run on the background and don't have to access the Unity API you can still do this by calling ConfigureAwait(false) then the SynchronizationContext will be "ignored" and the async "callback" will (in most cases) run on a background thread.

    • @whoisj
      @whoisj 5 років тому

      @@r1pfake521 Um.. . I hate to be the first to tell you this but tasks are just promise objects for interacting with work executed on other threads. They don't really exist, except as a logical model for understanding threading.

    • @GladerDev
      @GladerDev 5 років тому +10

      @@whoisj After reading both people's comments I have to say that your comment is very unhelpful. R1PFake's reply to Chavez about how async/await in .NET/C# is not implictly multithreading your code, and describing the purpose and meaning of the synchronization context which does control continuations, is a very appropriate answer to Chavez complaint.

    • @phobos2077_
      @phobos2077_ 5 років тому +2

      @@r1pfake521 Not to mention you can actually write Async methods that work via Unity's coroutines (via custom Awaiters returned from extension methods on, for example, YieldInstruction) - so you not only know your async methods are 100% work on main thread, you can actually control the context they work in (which is important for games with complex updates like ECS-based architectures with interdependent systems etc.)

  • @Flem100DK
    @Flem100DK 2 роки тому +2

    I think he was super good, I could actually follow! Thx for this mr. Suomi! :)

  • @irpgTV
    @irpgTV 4 роки тому +10

    Bad thing is WebGL still not support for async right now. I have trying to use async to load Addressable Asset but editor shows that it doesn't support right now...

  • @tuseroni6085
    @tuseroni6085 Рік тому +1

    i had recently needed to convert some coroutine logic to async entirely because i couldn't make it await a result.
    so in my case i had a message that would move across the screen using ui builder and transitions. i didn't want the next action to happen until the message for the current action had shown and gone (so for example i have a "program" called "Hellhound" in the game and it attacks my player "DEADFEED" it first has to spot him, if it does a message shows saying "Hellhound spotted DEADFEED" the hellhound then need to wait for that message to finish before moving on to its next action of attacking DEADFEED, and it should wait til that message is gone before showing the message for "HIT" or "MISS" and when that is done then it applies the damage and shows a message for that. the code also simulates a dice roll, but an option is available to get a dice roll from the user, a diceware option, so in that case when the hellhound looks for DEADFEED then a prompt would need to show up asking the player to roll 1D10 and put in the number, the REF would also be asked, if the game is being played in online mode, to roll 1D10
    so my enemies (programs) have logic that depends on the result of 1 or many asynchronous inputs or which has to wait for certain actions to continue.
    async made this much, much simpler, i had to make sure all my functions were async and returned a task, in the case of void, or task in the case of one that returns and i had to move the state machine out of a coroutine and into an async so it could await these results, but it's worked pretty nicely.

  • @imaginationrabbit
    @imaginationrabbit 5 років тому +6

    Great presentation- thank you.

  • @AndreaLeganza
    @AndreaLeganza 3 роки тому +1

    Every time i see on Unity docs and their videos the use of "public" i get chills...

  • @gecko6872
    @gecko6872 2 роки тому +2

    Super informative, but specifically for Unity and specifically for this use-case, why would using async/await as demonstrated be more efficient than
    instantiating a popup prefab, instantiating the desired number of buttons (using layout elements), and doing Button[i].OnClick().AddListener( () => some function(arguments) )
    It seems to me that, for pop-up boxes, it is more efficient and allows greater flexibility to assign the desired Actions directly to the buttons...

    • @tuseroni6085
      @tuseroni6085 Рік тому +2

      consider the following:
      if(!await GameController.RollToHit(target, this))
      {
      GameController.EndTurn(this);
      return 0;
      }
      (from gameController)
      public async Task RollToHit(NetActor target,NetActor Attacker)
      {
      ret=false;
      int D10= await MenuController.ShowMessageBox("Please Roll a D10");
      if((ProgramDefense + d10 + InterfaceTotal + Int) > target.defense)
      {
      ret=true;
      }
      return ret;
      }
      (inside MenuController a visualElement using uiElements)
      public async Int ShowMessageBox(string Message)
      {
      while (MessageBoxOpen)
      {
      await Task.Delay(250);
      }
      var newMessage = Message;
      MessageLabel.text = newMessage;
      MessageBoxOpen= true;
      MessageLabel.AddToClassList("Shown");
      while(MessageBoxOpen)
      {
      await Task.Delay(250);
      }
      return MessageBoxNum.Value;

      }
      i'm glossing over a few things and kinda refitting some code i have written here to demonstrate
      the biggest benefit here is that the code continues right after the input, and the ui is kept pretty separate from the main code (so the menucontroller handles the popup, and likely other ui elements, it handles the click on the ok and cancel to set that field "MessageBoxOpen" to false to allow the async call there to continue. this could also be getting its results from a socket to another program, doesn't matter to the calling program, it just waits to get a result back from...wherever...however the program wants to do it.)

    • @gecko6872
      @gecko6872 Рік тому

      ​@@tuseroni6085 Came back to say that your comment started me down the async road a few months ago, and I cannot imagine coding pop-up items without it anymore. Thank you!

    • @FredrikHAndersson
      @FredrikHAndersson Рік тому

      ​@@tuseroni6085 Is there a name to this pattern? Inhouse, I have made a very successful UI framework fully based on async like the speaker here hints at. It is incredible what the pattern has done for stability, cleanliness of code and iteration speed. So much that it ought to have a name and some recognition.

    • @FredrikHAndersson
      @FredrikHAndersson Рік тому +1

      @@gecko6872 I had a similar journey, but from being at this speech live :D

  • @OddStare
    @OddStare 5 років тому +19

    Good god almost fell asleep in the train back home good thing there is only two concepts to explain

  • @augustopinheiro
    @augustopinheiro 5 років тому +10

    I'm pretty confused about the popup example, why does he load a whole scene just for the popup? And why would he need to select the buttons? Sorry, I'm just pretty confused...

    • @Tech_Alchemy
      @Tech_Alchemy 5 років тому +1

      If you play the game he refers to it makes sense then.

    • @jonathansaindon788
      @jonathansaindon788 5 років тому +10

      It's easier to manage the UI lifetime by loading and unloading a scene (additive or not) than instantiating UI gameobjects directly, keeping references to them somewhere and destroying them at the end. It find it particularly usefull when switching between non-additive UI scenes. Like going from the multiplayer server list UI to the game loading UI for example. The server list UI only needs to know that when you click the Join button it loads the GameLoading scene non-additively so that ServerList UI gets destroyed.

    • @mandisaw
      @mandisaw 5 років тому

      I can imagine they might keep all their dialogs in a dedicated scene, with all accompanying logic, and then just call up that scene from anywhere with dialog parameters set as appropriate.

  • @sokrates297
    @sokrates297 5 років тому +2

    Perfect timing, thank you!

  • @sunnycareboo8924
    @sunnycareboo8924 4 роки тому +7

    Why not both?
    Unitask exists...

  • @tihomirgvero8454
    @tihomirgvero8454 4 роки тому +4

    Is there any official Unity documentation about Async?

  • @harrysanders818
    @harrysanders818 4 роки тому +2

    Enjoyable Talk! Clear explanations. Thanks very much

  • @MohammadFaizanKhanJ
    @MohammadFaizanKhanJ 2 роки тому

    My first experience with async .obj file loading, it is very very slow!

  • @snaecooceans8744
    @snaecooceans8744 5 років тому +18

    MORE DOTS

    • @pearz420
      @pearz420 5 років тому +3

      ok stop dots

    • @whoisj
      @whoisj 5 років тому +2

      ..............
      Sorry, had to.

    • @snaecooceans8744
      @snaecooceans8744 5 років тому

      @@whoisj Funny .. I'm still waiting for a polish product ..

    • @user-gl1ls1jx3h
      @user-gl1ls1jx3h 5 років тому

      KAAAY, DPS, SLOWLY

    • @MalrickEQ2
      @MalrickEQ2 2 роки тому

      @@user-gl1ls1jx3h And when I say slowly...I mean -

  • @cathrynm
    @cathrynm 2 роки тому +2

    I still hate 'var' -- var is like a cancer.

    • @MalrickEQ2
      @MalrickEQ2 2 роки тому +1

      Me too, I dunno why people like it. Our team doesn't allow it.

  • @nathanieldoldersum6169
    @nathanieldoldersum6169 5 років тому +2

    At 26:17 How do we fix it? (async throwing null reference). Why not just for the async write: `while (transform)` and it would stop if transform gets null and zero complexity added...

    • @tryfinally
      @tryfinally 5 років тому +8

      *while(this.transform)* will throw because the *this* reference will be null (or null-like) and the transform getter will throw, but indeed you can use *while(this)* and *if(this)* after awaiting to avoid this issue.

    • @nathanieldoldersum6169
      @nathanieldoldersum6169 5 років тому

      ​@@tryfinally Yep true...

  • @AnkitSingh-wq2rk
    @AnkitSingh-wq2rk 3 роки тому +2

    and here i am using async methods in coroutine bruh ...

  • @warcinm3210
    @warcinm3210 2 роки тому

    you used the Drake meme wrong, mate.

  • @leejim584
    @leejim584 3 роки тому +4

    This guy dose have some funny lines for audience but the problem is the way he delivers it...

    • @PavelFadrhonc
      @PavelFadrhonc 3 роки тому +4

      I, for one, quite enjoined his dry and somewhat awkward delivery. Suits his character it seems.

  • @nenicenerd
    @nenicenerd 4 роки тому +4

    как. же. он. медленно. говорит. делая. такие. долгие. паузы. что. даже. на 1.75 скорости. его. не возможно. слушать.

    • @JackFastGame
      @JackFastGame 3 роки тому

      Может это не его родной язык, поэтому ему тяжело?

  • @Valentyn90A
    @Valentyn90A 3 роки тому +1

    Nice memory leak in that PressButton async example *facepalm*

  • @Boolai
    @Boolai 5 років тому +2

    Jeeze. Can we get a little less boring. At least Mike makes it entertaining.

  • @sicksharkx92
    @sicksharkx92 4 роки тому +1

    PLEase GOD Change speaker........