Tests
Because Reflection is being used and slow/expensive at Runtime I did some testing
** Do not access or modify the UI, game objects, or anything that runs on Unity's main thread when using Async Events. An Exception will be thrown because Unity runs on the main thread and Async Events are called on potentially multiple threads depending on your system or the end user's system
A quick overview of terms used in the testing results tables below
Game Objects = An Object in Unity Scene, or class that inherits from MonoBehaviour
Normal Sync = Normal way of subscribing to events in a Synchronous manner
Dynamic Sync = Subscribe to events using Synchronous Attributes - because methods are invoked dynamically and are not actual events / Action delegates, there is no need to unsubscribe the event
Dynamic Async = Subscribe to events using Asynchronous Attributes - because methods are invoked dynamically and are not actual events / Action delegates, there is no need to unsubscribe the event
Dynamic Event Tests
Explanation of Test Tables Below
Blocks UI / Gameplay = If any method that is subscribed to an event does CPU intensive work (ex. for loop, foreach loop, synchronous call to FileSystem/IO, or synchronous HTTP call(web request)) the UI / Gameplay may pause and be unresponsive for a period of time. From the tests below a user will only notice this if you have many synchronous methods that are subscribed to Vivox Events. When possible, use Dynamic Async events or use Coroutines in Unity when using Synchronous Events to prevent Blocking/Unresponsiveness from the UI or Gameplay
For Loop - How many iterations of a for loop per method/event that was invoked. This is to simulate work being done after an event is fired. Example when a player joins Audio channel you loop thru some GameObjects or Instantiate them for the new player in the AudioChannel
Classes (1 event per class) = for every class on a game object there is only one method that is subscribed to a Vivox Event. Multiple classes will be on a game object to get more real-world results
Events Invoked = how many events were called for the test that was performed. Since every class only has 1 event being called/invoked then you can multiply game objects in test by the number of classes each game object has since every class only has 1 event.
Modify UI, Game Objects, call main thread = Depending on the type of event used, can I modify game objects? update the UI? (Unity UI is single threaded so async modifications to objects on the main thread will throw an exception. Also you may not receive an exception and the UI will still not update properly).
Seconds = how many seconds to complete/invoke all methods that have been subscribed to Vivox Events. Some tests took longer than 60 seconds as you will see below but most were more less than 60 so I kept the time interval as seconds
Normal Sync
1000
2
200
75.25 (1 min 15 seconds)
Dynamic Sync
1000
2
200
73.64 (1 min 13 seconds)
Dynamic Async
1000
2
200
33.42
Normal Sync
100
5
500
17.69
Dynamic Sync
100
5
500
21.50
Dynamic Async
100
5
500
8.05
Normal Sync
1
37.79
Dynamic Sync
1
42.44
Dynamic Async
1
18.18
Normal Sync
1
3.834
Dynamic Sync
1
4.078
Dynamic Async
1
1.835
Normal Sync
0
5
2,500
0.824
Dynamic Sync
0
5
2,500
1.171
Dynamic Async
0
5
2,500
0.349
Normal Sync
0
5
5,000
1.832
Dynamic Sync
0
5
5,000
1.934
Dynamic Async
0
5
5,000
0.508
5,000
Normal Sync
0
1
5,000
1.622
5,000
Dynamic Sync
0
1
5,000
1.891
5,000
Dynamic Async
0
1
5,000
0.716
Based on the results if you are not updating game objects, the UI, or Unity Specific Work/Functionality on the main thread then I would use Async Events. If you need to use Synchronous events, then use coroutines inside your method (If it makes sense) for better performance and to avoid blocking the main thread.
For Async games/apps where most functionality is async/multi-threaded consider using the Unity Job System(with DOTS) or combine async Task/void methods with Parallel.For / Parallel.ForEach when doing CPU intensive work. Parallel.For / Parallel.ForEach will still block the UI / main thread if not used with async void or async Task methods. Do your own research if you don't know how to use asynchronous or Parallel programming. The advice I have mentioned above is not for all use cases and also considered bad in most contexts (like async void or using async with Parellel.ForEach), especially outside of Unity Game Engine where async is the standard for performant applications. Keep in mind Parallel programming (as well as async) comes with a lot of gotchas that could make your code hard to debug or actually make performance worse if not used correctly. Do your own research and avoid async until you have a good understanding of how to use it in Unity
Last updated
Was this helpful?