Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

More efficient unity events

Discussion in 'Scripting' started by Deleted User, Aug 4, 2019.

  1. Deleted User

    Deleted User

    Guest

    Unity Events are great tool to keep your classes decoupled. But their performance is worse than C# events.
    I'm not expecting to achieve the same performance as C# native events with Unity Events. I want to know if there is anything that I can do to improve the performance of Unity Events.
     
  2. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    9,991
    https://jacksondunstan.com/articles/3335
    It is not that simple. UnityEvents can be worse than native C# events, but not if you have more than one listener. And obviously it depends on what measurement, time or garbage?
    The best way if you do it through interfaces. Example here: https://jacksondunstan.com/articles/3335#comment-713798
     
  3. Deleted User

    Deleted User

    Guest

    Thank you for your response.
    A big feature of Unity Events is that they are assignable through inspector. And you can add listeners without touching the code. But in the interface version it is required to change every class that wants to be a listener to a specific event.

    As I said, I'm just looking for general optimization tips (if there are any). On both time and garbage.
     
  4. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,454
    Do you use these events for more than occasional "button press events" for example? For what things do you use them that makes it worthy to optimize?
     
    Lurking-Ninja likes this.
  5. Deleted User

    Deleted User

    Guest

    We have different kind of events in our game. Some of them are occasional, some others happen in quick successions for a short amount of time, Some happen at constant rate, etc.

    I don't know which one of them is good to be converted to Unity Events. What kind of events are best for Unity Events? In what conditions they work "optimally"?
     
  6. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,454
    I use Unity Events pretty much for UI only, button presses and things like that.

    When Unity Events was new, I recall I used them for a method that was called every frame, but noticed every call allocates garbage memory. Since then I never tried to use Unity Events for more than occasional buttons clicks. I don't know if they fixed the garbage issue, I believe it was around Unity 4.6 or perhaps 5.0.

    If it's important to be able to wire method calls through the Inspector, then it probably makes sense to use Unity Events. But if it's slow, generates garbage and it turns out to be a problem, then I would look for alternatives.

    Regular C# events come to mind. However, if add and remove events often during Update, it also generated garbage as far as I recall. Depending on the context, I often prefer interfaces over delegates, just because adding and removing them to a list does not generate garbage and I find calling methods through an interface easier to debug than delegates.

    I went into a bit more detail on it in this thread: https://forum.unity.com/threads/world-manager-generic-world-management-system.484239/#post-3154969

    Just search for "We moved away from using this kind of event subscription" and then you found my explanation.
     
    Deleted User likes this.
  7. Deleted User

    Deleted User

    Guest

    I did some tests. Here are my scripts:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Events;
    3. using UnityEngine.Profiling;
    4.  
    5. public class Listener : MonoBehaviour
    6. {
    7.     [SerializeField] private int unitySum;
    8.     [SerializeField] private int normalSum;
    9.  
    10.     public void AddUnityListeners()
    11.     {
    12.         Profiler.BeginSample("AddingUnityEventListener");
    13.         var unityEventTest = GetComponent<UnityEventTest>();
    14.         UnityAction<int> unityAction = UnityCall;
    15.         for (int i = 0; i < 1000; i++)
    16.         {
    17.             unityEventTest.Test.AddListener(unityAction);
    18.         }
    19.  
    20.         Profiler.EndSample();
    21.     }
    22.  
    23.     public void AddNormalListeners()
    24.     {
    25.         Profiler.BeginSample("AddingNormalEventListener");
    26.         var normalEventTest = GetComponent<NormalEventTest>();
    27.         NormalEventTest.Method method = NormalCall;
    28.         for (int i = 0; i < 1000; i++)
    29.         {
    30.             normalEventTest.Test += (method);
    31.         }
    32.  
    33.         Profiler.EndSample();
    34.     }
    35.  
    36.     private void UnityCall(int arg0)
    37.     {
    38.         unitySum += arg0;
    39.     }
    40.  
    41.     private void NormalCall(int arg)
    42.     {
    43.         normalSum += arg;
    44.     }
    45. }
    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using UnityEngine.Events;
    4.  
    5. public class UnityEventTest : MonoBehaviour
    6. {
    7.     [Serializable]
    8.     public class SomeEvent : UnityEvent<int>{}
    9.  
    10.     public SomeEvent Test;
    11.  
    12.     public void Update()
    13.     {
    14.         Test.Invoke(5);
    15.     }
    16. }
    17.  
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class NormalEventTest : MonoBehaviour
    4. {
    5.     public delegate void Method(int arg);
    6.  
    7.     public event Method Test;
    8.  
    9.     private void Update()
    10.     {
    11.         if (Test != null)
    12.         {
    13.             Test(5);
    14.         }
    15.     }
    16. }
    And these are the results:
    Code (CSharp):
    1. Adding 1000 Unity Event listeners:    39 KB allocated memory.    2.6 ms
    2. Adding 1000 Normal Event listeners:   4 MB allocated memory.     10.9 ms
    3. Invoking Unity Event in every frame:  0 allocated memory.        2.5 ms (Per frame)
    4. Invoking Normal Event in every frame: 0 allocated memory.        0.25 ms (Per frame)
    Unity devs have done a really good job with Unity Events.
    ~2 ms in invoking Unity Events is because of null checks that unity does. It's probably what you want anyway. You don't want to get missing references when calling events.

    In conclusion, Unity Events are already really high performance. I don't think that you can get any faster with these kind of events.
     
    trombonaut, Plaximo, KinanGH and 5 others like this.
  8. TeacherMax

    TeacherMax

    Joined:
    Jan 27, 2019
    Posts:
    9
    Sorry to necropost, but seriously - these figures literally show native C# events being 10x faster than Unity events so the phrase "Unity Events are already really high performance. I don't think that you can get any faster with these kind of events." is somewhat misleading.

    (I came here to find exactly this info, so thanks for posting it, but it's native C# events for me, every time!
     
  9. aguskos

    aguskos

    Joined:
    Jan 17, 2017
    Posts:
    5
    Please note that it's not that unity events are slow it's delegates are very fast. I run same test in build a while ago and unity events is roughly 11x slower than delegate but both GetComponent and changing position are 4x slower than unity events and toggling game object activate state is 6-7 slower than that. So toggling active state is roughly 300 slower than delegate call.
     
    DungDajHjep likes this.