UnityAsync icon indicating copy to clipboard operation
UnityAsync copied to clipboard

How does this compare to https://github.com/modesttree/Unity3dAsyncAwaitUtil

Open rib opened this issue 4 years ago • 4 comments

It looks like this project is more up to date and perhaps better maintained than this Unity3dAsyncAwaitUtil project and since I'm currently using Unity3dAsyncAwaitUtil I'd be interested to learn if there are some specific technical pros/cons for each one to help decide whether to use this project instead.

It would be good if the documentation could highlight if there are any key technical differences between this and any other alternatives.

rib avatar May 11 '20 17:05 rib

From a quick glance at the example API usage and source code, Unity3DAsyncAwaitUtil appears to focus more on utility/convenience without much concern for performance. Most of the await instructions seem to spin up a Coroutine, which isn't something you want to do too often, especially in a next update loop (where a Coroutine would be created every frame). All await instructions are classes, which means they're always heap allocated. Generally, an await instruction is used as a throwaway object – its lifespan doesn't last more than a few seconds or even a frame, and once it's done, it becomes garbage and must be cleaned up by the garbage collector (which can result in noticeable frametime spikes if they build up – recent Unity versions improve this but it's still something to avoid). A few of the per-frame await instructions are statically cached to avoid allocations but you can't do this with configurable ones like WaitForSeconds.

UnityAsync's main performance goal is to not cause any unnecessary heap allocations. It does so by implementing all await instructions as structs, which will sit on the stack in a normal async method. Of course, some aspects of async are heavily tied to the Task API and tasks are always heap allocated so there's only so much you can do. For example, awaiting an async method requires the allocation of a Task object, but if you don't need to await it (like starting a Coroutine without caring when it ends), you can make it async void and it probably won't allocate any heap memory. It also runs fast – faster than Unity Coroutines, and allows you to not have to rely on YieldInstructions.

Pros:

  • Faster than Unity Coroutines.
  • Faster than Unity3dAsyncAwaitUtil.
  • Always reduced heap allocations compared to Unity3dAsyncAwaitUtil.
  • Reduced heap allocations compared to Unity Coroutines if used carefully.

Cons:

  • A bit over-engineered (relying on only structs requires a lot of generics and boilerplate, though this complexity is not exposed to you – you don't need to worry about it).
  • Introduces a new kind of await instruction; now you have to consider when to use a (Custom)YieldInstruction versus an IAwaitInstruction (use the latter with async coroutines where possible and the former otherwise).
  • If you only care about speed, there are IEnumerator-based Unity coroutine libraries out there which will outperform this substantially (usually not compatible with existing Unity YieldInstructions) – async methods carry a certain (rather small) amount of overhead.
  • Doesn't play nice with the new Editor Play Mode settings, but then many assets don't and most users end up having to disable the settings anyway.

If the concern is compatibility, both libraries are compatible with Unity's IEnumerator coroutines and YieldInstructions. For ease of use, Unity3dAsyncAwaitUtil might have a slight edge due to being simpler and using existing YieldInstruction API. If the concern is performance, UnityAsync is probably the best performing async coroutine library around. I'd give UnityAsync a try – you can use it as little or as much as you wish, so long as that last con doesn't bother you.

muckSponge avatar May 18 '20 00:05 muckSponge

I should add, I wrote the pros and cons and discussion here for you. I'm not so sure about adding it to the README because I don't want to be openly critical of other libraries, but I understand your point and I'll consider adding something to the README to objectively compare with and direct people to a few alternatives.

muckSponge avatar May 18 '20 00:05 muckSponge

Thanks @muckSponge this is really helpfull. Understandable that you don't want to be openly critical of other projects and maybe 'pros/cons' wouldn't be the best way of presenting differences in the README but maybe some of the same information can still be explained. So long as the focus is on technical details then hopefully others can decide how that translates into pros/cons for their specific use cases. Thanks again!

rib avatar May 18 '20 10:05 rib

Is there actually performance benchmarks to back up some of these claims?

StephenHodgson avatar Oct 01 '20 14:10 StephenHodgson