Zero-Overhead async/await for Unity by custom async statemachine with C# 7.0

Unity supports async/await from Unity 2017, it is great feature but not used widely now. Why? The main reason is framework(Unity) does not provide await support to AsyncOperation. This is not all, standard Task operations is thread base, it is not match to Unity. Finally performance, Task can not avoid some overhead.

I’ve created library that resolve there all issues. This is the sample code of it.

UniRx.Async! Yes, I am the author of UniRx and today I’ve released a new version(v6.0.0) on Unity Asset Store and GitHub releases page. Update details, please see UniRx/releases/6.0.0 but here is not talk about UniRx.

UniRx.Async is an independent feature with UniRx, It can add without UniRx(in releases page, providing UniRx.Async without UniRx unitypackage).

UniRx.Async provides many features based on custom async statemachine builder, it does not use Task and SynchronizationContext. Completely built on continuation.

Overhead of standard Task

Anyway, let’s try to see the details by Profiler.

This details spans two frames of await frame and completed frame.

Image for post
Image for post
Task’s await frame
Image for post
Image for post
UniTask’s await frame

Task is checking ExecutionContext many times but UniTask omit completely.

Image for post
Image for post
Task’s complete frame
Image for post
Image for post
UniTask’s complete frame

UniTask is more simple, less overhead and less garbages.

What is UniTask? UniTask consists of a struct value holder and a custom async state machine builder. Custom async state machine builder can controls how handle async/await in C#. So I decided to create zero-overhead async/await system that tight-coupled with Unity.

Unity C# is run on C++ Game Engine and it driven by single-thread. For example AsyncOperation.completed += action event is invoked by engine and it is already returned main-thread. That is, basically no SynchronizationContext is needed.

Frame Operations

Image for post
Image for post

If you encounts unknown errors, please try to downgrade IncrementalCompiler version.

When move from coroutine, we notice async/await has no frame operations. yield return null, yield return WaitForEndOfFrame, etc. And the Task.Delay is thread-pool based timer operation, it is too heavy and not suitable for Unity.

UniTask provides frame based Delay and Yield.

// continue after next 100 frame.
await UniTask.Delay(100);
// continue after PostLateUpdate
await UniTask.Yield(PlayerLoopTiming.PostLateUpdate);

There are work on PlayerLoopSystem introduced in Unity 2018(experimental). It can await EarlyUpdate, FixedUpdate, PreUpdate, Update, PreLateUpdate, PostLateUpdate, you can choose own timing.

There are completely no use thread. So does not need SynchronizationContext marshaling cost and perfectly works on WebGL.

Rx vs coroutine vs async/await

However, standard async/await can not replace Rx and coroutine because it is very poor to use in Unity. UniRx.Async can be replaced by many functions.

Rx has many sides and functions. Rx’s event streams and reactive programming is still good. Asynchronous to use async/await, Event to use Rx. We can use both so it is the better paradigm.

The future of UniRx

Today, I’ve rebooted UniRx. I should maintain and improve to support great game development and to prove power of C#. Sorry, I did not watched many issues and PR! I’ve started checked and triage issues.

Both UniRx and UniRx.Async can add many features. I’ll keep development.

I've started Open Collective, https://opencollective.com/unirx . If you want to support development, you can donate/become a bucker/become a sponsor. If I can create development time many more, will be very happy.

Written by

a.k.a. neuecc. Creator of UniRx, UniTask, MessagePack for C#, MagicOnion etc. Microsoft MVP for C#. CEO/CTO of Cysharp Inc. Live and work in Tokyo, Japan.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store