coroutines are great in Unity, but I also see them being used like it's "free cost" in situations where it's not the best solution, sometimes killing many framesPerSecond in the process, if we scale certain situations/component up to hundreds of instances.

@djlink Have you used the "new" async/await support in Unity? I've been trying it out and while it does initially feel more complex (but more capable), it does feel like it would be cleaner to use, after getting used to it.

My worry is that all code written with async/await would then become virtually unmaintainable to a lot of developers whom aren't used to that workflow.

@silva rarely tbh, unless there's a good case I mostly avoid things that might cause what you just described, cleaner for every dev is usually preferable.

@djlink @silva note that async/await is not connected to a gameobject lifetime. This means that a forever async task will run forever and must be manually cancelled.

Both have the same GC accumulation issues of reach yield/await thoug. So it's better to use them sparingly and only when:
1. waiting for something to finish (load, download, etc)
2. Doing something in stages e.g. a cutscene.

I wouldn't use them in other contexts. Any other use case surely has a better more optimized alternative.

@djlink @silva probably the advantage of async/await over coroutines is that they are effectively a thread. Whereas coroutines are not. This mean really intensive/long single tasks wouldn't block the main thread.

But other than that if you want to do multiple* (I.e. on many, many multiple objects) intensive tasks, that's why you use the jobs system for that.

@glitchypixel @djlink Hey! Thanks for your input! I think those are all important points. In regards to the comment on using jobs, that's been my approach. When I have one task I need to move out of the main thread, I just use an Async method.

When working on Dawn of Defense, we had to do map generation, which was blocking the main thread for roughly 6 to 7 seconds (on my machine). After switching to an async method, we could then have a loading screen while the map is generating.

@glitchypixel @djlink Could you elaborate on what the better alternatives are to using Async/Coroutines? Like doing everything on update? Including waiting for some condition/time?

I find that for me, when using Async methods, my code becomes cleaner, as opposed to doing things on update/Coroutines. The methods start becoming very single purpose and organized, although I then have this whole complexity of lifecycle management to deal with, which does often hurt readability.

@silva @glitchypixel personally I try to use Update, actually today I switched a bunch of coroutine code to the respective component Update() to great performance effect in this particular case. It was hundreds of objects spawning coroutines

@djlink @silva yup that is a good optimizing step. Multiple objects with each one using coroutines is not good at all. Wouldn't use async either actually.

I don't see something better than that as a solution. Maybe have a good structure on what you are making (e.g. maybe a fsm if warranted) but otherwise yeah that's good.

Next step would be to, well use jobs + burst compiler actually if you want even better optimization.

At that moment you are basically using ECS for critical path components.