Best practices: Async vs. coroutines - Unite Copenhagen

Sdílet
Vložit
  • čas přidán 29. 08. 2024

Komentáře • 61

  • @manituan4956
    @manituan4956 Před 4 lety +61

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

  • @jeangodecoster
    @jeangodecoster Před 4 lety +76

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

    • @chromezephyr8959
      @chromezephyr8959 Před 10 měsíci +1

      This. Scriptables that have functionalities inside must use async.

  • @masonwheeler6536
    @masonwheeler6536 Před 4 lety +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?"

  • @slowdragon4169
    @slowdragon4169 Před 4 lety +26

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

  • @mandisaw
    @mandisaw Před 4 lety +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

  • @Flem100DK
    @Flem100DK Před 2 lety +2

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

  • @IbakonFerba
    @IbakonFerba Před 4 lety +10

    Using this for UI solves so many problems!

  • @imaginationrabbit
    @imaginationrabbit Před 4 lety +6

    Great presentation- thank you.

  • @FranciscoTChavez
    @FranciscoTChavez Před 4 lety +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 Před 4 lety +15

      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 Před 4 lety

      @@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 Před 4 lety +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_ Před 4 lety +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.)

  • @irpgTV
    @irpgTV Před 4 lety +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...

  • @sokrates297
    @sokrates297 Před 4 lety +2

    Perfect timing, thank you!

  • @OddStare
    @OddStare Před 4 lety +19

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

  • @augustopinheiro
    @augustopinheiro Před 4 lety +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 Před 4 lety +1

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

    • @jonathansaindon788
      @jonathansaindon788 Před 4 lety +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 Před 4 lety

      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.

  • @tuseroni6085
    @tuseroni6085 Před rokem +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.

  • @AndreaLeganza
    @AndreaLeganza Před 3 lety +1

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

  • @sunnycareboo8924
    @sunnycareboo8924 Před 3 lety +7

    Why not both?
    Unitask exists...

  • @harrysanders818
    @harrysanders818 Před 4 lety +2

    Enjoyable Talk! Clear explanations. Thanks very much

  • @tihomirgvero8454
    @tihomirgvero8454 Před 4 lety +4

    Is there any official Unity documentation about Async?

  • @gecko6872
    @gecko6872 Před rokem +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 Před rokem +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 Před rokem

      ​@@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 Před rokem

      ​@@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 Před rokem +1

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

  • @snaecooceans8744
    @snaecooceans8744 Před 4 lety +18

    MORE DOTS

    • @pearz420
      @pearz420 Před 4 lety +3

      ok stop dots

    • @whoisj
      @whoisj Před 4 lety +2

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

    • @snaecooceans8744
      @snaecooceans8744 Před 4 lety

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

    • @user-gl1ls1jx3h
      @user-gl1ls1jx3h Před 4 lety

      KAAAY, DPS, SLOWLY

    • @MalrickEQ2
      @MalrickEQ2 Před 2 lety

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

  • @MohammadFaizanKhanJ
    @MohammadFaizanKhanJ Před 2 lety

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

  • @nathanieldoldersum6169
    @nathanieldoldersum6169 Před 4 lety +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 Před 4 lety +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 Před 4 lety

      ​@@tryfinally Yep true...

  • @AnkitSingh-wq2rk
    @AnkitSingh-wq2rk Před 3 lety +3

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

  • @cathrynm
    @cathrynm Před 2 lety +2

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

    • @MalrickEQ2
      @MalrickEQ2 Před 2 lety +1

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

  • @warcinm3210
    @warcinm3210 Před 2 lety

    you used the Drake meme wrong, mate.

  • @leejim584
    @leejim584 Před 3 lety +4

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

    • @PavelFadrhonc
      @PavelFadrhonc Před 3 lety +4

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

  • @nenicenerd
    @nenicenerd Před 4 lety +4

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

    • @JackFastGame
      @JackFastGame Před 2 lety

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

  • @Valentyn90A
    @Valentyn90A Před 3 lety +1

    Nice memory leak in that PressButton async example *facepalm*

  • @Boolai
    @Boolai Před 4 lety +2

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

  • @sicksharkx92
    @sicksharkx92 Před 4 lety +1

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