Comparison of Unity(C#) Messaging / Events Systems

Discussion in 'Scripting' started by lacost, Mar 10, 2013.

  1. lacost

    lacost

    Member

    Joined:
    May 30, 2012
    Messages:
    661
    Flash Like Event System
    https://www.assetstore.unity3d.com/#/content/7067

    How add listener
    Code (csharp):
    1.  
    2. MyButton btn = gameobject.addComponent<MyButton>();  // creating some simple button
    3. btn.addEventListner(BaseEvent.CLICK, onButtonClick);  // listening event
    4.  
    How to dispatch event
    Code (csharp):
    1.  
    2. //MyButton.cs
    3.  
    4. void OnGUI() {
    5.     if(GUI.Button(buttonRect, "click me")) {
    6.         dispatch(BaseEvent.CLICK, "hello");  //second param is optional and can be any object.
    7.     }
    8. }
    9.  
    Speed result on 100 000 events - 85ms
    [HR][/HR]

    Standar Unity Send Message
    http://docs.unity3d.com/Documentation/ScriptReference/Component.SendMessage.html

    Speed result on 100 000 events - 100ms
    [HR][/HR]

    CSharp Event Manager
    http://wiki.unity3d.com/index.php/CSharpEventManager

    How add listener
    Code (csharp):
    1.  
    2.  EventManager.instance.AddListener(this as IEventListener, "TestEvent");
    3.  
    How to dispatch event
    Code (csharp):
    1.  
    2. EventManager.instance. TriggerEvent(new TestEvent());
    3.  
    Speed result on 100 000 events - 145ms
    [HR][/HR]

    Advanced CSharp Messenger
    http://wiki.unity3d.com/index.php/Advanced_CSharp_Messenger

    How add listener
    Code (csharp):
    1.  
    2.  Messenger.AddListener("start game", StartGame);
    3.  
    How to dispatch event
    Code (csharp):
    1.  
    2. Messenger.Broadcast("start game");
    3.  
    Speed result on 100 000 events - 45ms
    [HR][/HR]

    CSharp Notification Center
    http://wiki.unity3d.com/index.php/CSharpNotificationCenter

    How add listener
    Code (csharp):
    1.  
    2.  NotificationCenter.DefaultCenter.AddObserver(this, "OnBumperCollision");
    3.  
    How to dispatch event
    Code (csharp):
    1.  
    2. NotificationCenter.DefaultCenter.PostNotification(this, "OnBumperCollision");
    3.  
    Speed result on 100 000 events - 227ms
    [HR][/HR]

    –°onclusion: this is only my opinion, but I like AS3 event system, so "Flash Like Event System" is most comfortable to use and it's pretty fast.

    If You need free script, you should choose "Advanced CSharp Messenger", usage is almost like other's event systems, it steel static, but it's fastest.
    Last edited: Mar 11, 2013
  2. exiguous

    exiguous

    Member

    Joined:
    Nov 21, 2010
    Messages:
    985
  3. lacost

    lacost

    Member

    Joined:
    May 30, 2012
    Messages:
    661
    Thx, I will add it.
    By the way if this post was helpful, let me know, and I will do much more detailed description with code examples.
  4. exiguous

    exiguous

    Member

    Joined:
    Nov 21, 2010
    Messages:
    985
    i found it very helpfull as i always wondered about the runtime performance of each of this systems. but i was to lazy to test it and decided for advanced C# Messenger for convenience reasons. not the worst choice as it seems. but i have modified it alot and call it via enum instead of a string to allow obfuscating and prevent silly typo errors with strings.

    i wonder why your send message test is that fast. from what i read it should be far slowest solution (reflection). maybe you have only one script with one method attached? there had been a discussion about this some time ago but i have no link at hand.

    generally the measurements are only a rough indicator for execution speed as it depends on cicumstances (number of events, number of subscribers etc) and maybe even platform. retrieving an object from a generic dictionary is close to a O(1) operation relatively independant from the count (given the hash function matches the size and there are no/few collisions). so it is a good data structure for storing the events.

    i have never worked with actionscript and thus your flash like event system looks not very familiar to me. also it requires unity-components and is only available for gameobjects. most of my classes are non-monobehaviors and when i can't send them notifications the system as well as sendmessage is useless for me.

    but thanks for your efforts anyway as many people may wonder about performance and (dis)advantages of these systems in general. maybe it would be usefull when you create a wikipage and add your findings there and link to the systems. so people have a better overview than in a forum thread as it seems the forum search is not available to many people for some reason (or they are simply to lazy). who looks in the wiki is already willing to search what he/she needs.
  5. lacost

    lacost

    Member

    Joined:
    May 30, 2012
    Messages:
    661
    This was kind of a light testing. Every system was tested with only one listener and one dispatcher. So "Send Message" was tested with only one script with few methods.

    But you write, I will do new test and add result's with "loaded system", when we have a lot of listeners.

    Yes it has total different events ideology, that's why it not static or siglethon like others.

    No, it's not. It can work in both ways. Point is, that it has two class (EventDispatcher -> MonoBehavior) - for gameobjects, and
    (EventDispatcherBase - > Object) - for others.

    thx, this is good idea. I will do that as soon as I will finish "loaded" test's and add few more systems.
  6. vexe

    vexe

    Member

    Joined:
    May 18, 2013
    Messages:
    165
    Hey @lacost, thanks a lot for sharing your benchmarks - Have you considered this http://www.willrmiller.com/?p=87 ? - I wonder where it would sit in your scale - as I found it interesting.
  7. Agostino

    Agostino

    Member

    Joined:
    Nov 18, 2013
    Messages:
    20
  8. angrypenguin

    angrypenguin

    Member

    Joined:
    Dec 29, 2011
    Messages:
    4,851
    Some of those results are pretty surprising, though it should be noted that the different systems may have different characteristics in different usage scenarios.

    Also, what about a delegate based system? You probably won't find a pre-written one because there's actually nothing to pre-write. You just define a public delegate somewhere as your event notification function, and anything that cares about that event adds a matching internal function to the delegate.

    You'll also want to look at things like whether firing messages causes allocation.

    But also also... it's worth pointing out that you really need to think about whether performance of your event system matters in your use case. How often are events fired? I have a game which has a crap event system and a lot of spaghetti-like usage but, due to when events are fired, it makes no difference to the game's performance. (In that system there is no filtering of events, and events are reference objects and therefore caused allocation. So a typical event caused some allocation and then called dozens of functions that weren't relevant to it. "Optimise event system" is something that's been on our to-do list for ages but we've never got to it because it literally makes zero practical difference in our case.)
    Last edited: Dec 16, 2013
  9. JoeStrout

    JoeStrout

    Member

    Joined:
    Jan 14, 2011
    Messages:
    294
    I think the irate waterfowl has a point. I looked at these above (thanks to this very helpful thread) a few weeks ago, and ended up not using any of them. Instead I implemented my own which has a few features I really wanted: (1) broadcasters and receivers can come and go at any time, with no registration/unregistration step; (2) messages could be scoped either globally, or to the local GameObject, or to that GameObject and its contained objects (recursively); (3) messages could be referenced by name, making it easy to use them as triggers configured in the Unity editor; (4) no magic-named methods that's going to cause stuff to silently break just because of apparently-innocent refactorings; (5) no strong references causing objects to leak if you forget to clean them up.

    I achieved all these aims, but as a result, the performance on a per-message basis is a bit poor. Probably worse than any of the above, in fact. But the way we're using them, I really don't care; they don't have any noticeable effect on the framerate. I love how cleanly they separate concerns in the code in just the ways I need them separated, and I'm more than willing to pay a small performance penalty for that.

    Of course, different strokes for different folks, YMMV, never eat spinach with a stranger, etc.
  10. Dustin Horne

    Dustin Horne

    Member

    Joined:
    Apr 4, 2013
    Messages:
    1,409
    Interesting. My first Unity test project was a messaging system much like JoeStrout's above. It did use events but handled it in an interesting way. It was a generic system with a message manager. I created MonoBehaviors to act as subscribers to the messages. You could create your own classes and subscribe / handle messages... or you could use the Behavior helpers which would handle receiving messages for you. You could control the max number of messages, how many were processed at a time and how often it processed them (or process manually) and the messages were delivered and stored in a Queue<T>

    The entire system is generic and allows you to create subscriptions for different message types. If you subscribe like so:

    Code (csharp):
    1.  
    2. gameObject.SubscribeToMessage<Vector3>("ImHere");
    3.  
    It's an extension method that sets up the proper subscribers for you and adds the subscription. Now whenever someone calls:

    Code (csharp):
    1.  
    2. MessageBusManager.SendMessage<Vector3>("ImHere", transform.position);
    3.  
    That message gets sent out to all of the subscribers. You can handle the messages yourself OR you can setup events on your game objects and have the subscription process and send them for you. Also, the Subscriptions are stored as a WeakReference<T> and when they are garbage collected they are automatically purged from the subscription manager.

    Now this was my first Unity test so it needs a lot of work. I was leveraging some foreach loops because I have message subscriptions stored in a Dictionary and it generates garbage like mad every frame. :) It's something I'm going to go back and develop on eventually and implement my own custom collections and indexers so I don't deal with the per-frame garbage generation.

    Here's the original documentation for what I had started:
    http://www.parentelement.com/documentation/messaging/
    Last edited: Dec 16, 2013
  11. paskal007r

    paskal007r

    Member

    Joined:
    Sep 6, 2013
    Messages:
    12
  12. demminik

    demminik

    Member

    Joined:
    Aug 13, 2013
    Messages:
    5
    Such errors could be prevented by using constants, not string literals directly.
    Just testet the Advanced CSharp Messenger's performance with enum keys and results were not ones I expected (results per 100k broadcasts):
    - using string keys: 0.021 to 0.028 sec
    - using enum keys: 0.06 to 1.1 sec

    EDIT: Tested EventSystem from this thread http://forum.unity3d.com/threads/112449-Advanced-C-Messenger/page2. Performance per 100k broadcasts is 0.002 to 0.003 sec.
    Last edited: Feb 11, 2014
  13. exiguous

    exiguous

    Member

    Joined:
    Nov 21, 2010
    Messages:
    985
    sure it could. but none of the messenger/notification systems i'm aware of utilizes them. and those constants also have to remembered. when using an enum all possible values are "collected" at a central place. also you can iterate over the values of an enum, switch them etc.. so you gain alot functionality and "convenience" what you don't really have with strings or other "hacks". if you ask me i think thats what enums are made for so why intentionally ignore them?

    as enums are value types there is a little annoying discrepancy when using them as dictionary keys as they are boxed. so make sure you use an appropriate equality comparer to unleash their performance power. in my tests they have been faster than int keys with a custom comparer (have not tested strings).

    edit: the manual comparer has been 10 to 15 times faster than the default comparer! the both suggested automatic/generic solutions have been half as fast.
    Last edited: Feb 11, 2014
  14. LightStriker

    LightStriker

    Member

    Joined:
    Aug 3, 2013
    Messages:
    1,354
    I'm wondering about the exact step used for testing those systems.

    1 listener? What does the receiving method does? Since it's single-threaded, what the receiving method does has a huge impact on the performance.

    Also depends of the computer... At work - on my crappy computer - I get 24ms on our own event system for 100,000 dispatch over 1 listener with an empty callback method..
    Last edited: Feb 11, 2014
  15. exiguous

    exiguous

    Member

    Joined:
    Nov 21, 2010
    Messages:
    985
    if you refer to my "tests" with this statement i was a bit unclear. i just wanted to verify the performance impact of the "crappy" default comparer described in the linked site. so my test was not the whole messaging system but simply different dictionary key setups. and i could confirm that enum keys with default comparer is a bad idea and that there should be a custom comparer specified to avoid this issue.
    when you use such a messaging system i think its not for performance reasons but for convenience or "necissity". and for usual usecases (below 1000 anything) i think there should not be a performance issue. so if it is too slow for your taste can you replace it at all?
    so to clarify again: demminik "complained" about enum dictionary keys beeing slow, i told him why and proposed an easy method to improve it. my statement was NOT regarding overall performance of such event systems. and i'm still convinced that enums as keys are the best you can get. better than strings in any case for the mentioned reasons.
  16. LightStriker

    LightStriker

    Member

    Joined:
    Aug 3, 2013
    Messages:
    1,354
    I meant the first post of this thread.
  17. demminik

    demminik

    Member

    Joined:
    Aug 13, 2013
    Messages:
    5
    Ahh, I see now. Thx for the link, was very useful to me!
  18. rocki

    rocki

    Member

    Joined:
    Aug 10, 2012
    Messages:
    1,049
    @Dustin,

    Your Event system looks great. I was searching for a flexible and dynamic event system.
    I would love to have a copy of the project.

    Cheers.
  19. Dustin Horne

    Dustin Horne

    Member

    Joined:
    Apr 4, 2013
    Messages:
    1,409
    Sure! I'll see if I can get it packaged up for you. It needs a lot of work. Now that I've learned a lot more about Unity I realize it needs some optimization. :) The event dispatching works very well but it's enumerating a dictionary which allocates 30k every frame. I'm thinking about rewriting a good portion of it to implement custom collections and get rid of that allocation. Also, it auto manages the subscribers but only makes sure they're not null before dispatching events. I realize now that the game objects can be marked for destruction without being destroyed so I need to update the subscriber component so it unsubscribes itself automatically when OnDestroy is called. But I'll share the full source that's there now and you're welcome to play around with it.
  20. Dustin Horne

    Dustin Horne

    Member

    Joined:
    Apr 4, 2013
    Messages:
    1,409
  21. matheuslr

    matheuslr

    Member

    Joined:
    Aug 27, 2013
    Messages:
    6
    Hey, I too had some troubles trying to find the best solution for event management in Unity. So far, I wasn't able to find a proper one that satisfied my needs. So I decided to roll my own EventManager. It's a simple but effective solution to events in Unity.

    Please, check the code out at https://bitbucket.org/matheuslessarodrigues/connectr/ I'm looking for feedbacks :)

    I was looking for a way to get rid of that nasty "SendMessage()". Also, I tried to keep it really simple and unobtrusive as you don't require to define classes or implement some IEvent interface. Just mark your methods as an EventHandler (with C# attributes) and trigger events with a static method call. Like this:

    // Define the event with the method signature
    delegate void MyEvent( int, string, float )

    // Listens to "MyEvent"
    [Handlr( typeof( MyEvent ) )]
    void MyEventHandlerMethod( int some, string random, float args )
    {
    // Do your magic here...
    }

    // Then rais events with
    Connectr.Trigger<MyEvent>( 42, "The event params", 0.5f );


    Also, the subscription to events is handled by unity components automatically! :)
    What do you guys think?

    EDIT: sorry, I'm not used to forums so I don't know how to properly format my code x)
  22. LightStriker

    LightStriker

    Member

    Joined:
    Aug 3, 2013
    Messages:
    1,354
    You do it by reflection... Which I would wonder about the performance cost of having multiple object trying to register to the same event at the same time.
  23. matheuslr

    matheuslr

    Member

    Joined:
    Aug 27, 2013
    Messages:
    6
    Sure I am! But also, it will "compile" the listener call into a delegate so the performance is almost almost like a regular method call!

    * Thanks for the feedback, tho!
  24. lordofduct

    lordofduct

    Member

    Joined:
    Oct 3, 2011
    Messages:
    791
    I have my own Notification system as well.

    I rolled my own because I don't like strings representing my events. Instead I went with a class that represents the event, and an instance of this class is a parameter of the event handler, so to include any params, or what I call a 'Notification'. This creates an overhead of having to create said notification object when the notification occurs, but I was willing to take said performance hit for the added functionality of it. For instance, I can allow the messenger to "PostNotification", and the notification once done could come back with data. Allowing for things like cancelable events like you can do with .Net/mono EventArgs.

    I also expanded on what can be observed. Any single object, no matter the type, can dispatch a notification. But if that object is what I call a 'gameobject source' (gameobject, component, IComponent), I'll dispatch on the gameobject as well. So this way if say component 'GroundingResolver' dispatches notification 'LandedNotification', we can listen directly to the component OR to the gameobject the component is attached to.

    Furthermore I have a set of tools to represent what I call an 'entity'. Basically it's a 'root' gameobject that is flagged as being the root. All gameobjects inside of it are considered conjoined as a complete 'entity'. I may have multiple child gameobject representing various things... one gameobject may be the AI rig, another the motion controller, deep down a tree will be a weapon maybe. All of these things need to intercommunicate with messages as well. So I also have a for a raised notification to be sent not just to the component, not just to the gameobject that owns the component, but also to the root gameobject. So this way I can listen on the root for a notification to occur, and I'll receive it, and the Notification object that comes with it gives me the information about which specific object dispatched the notification.

    I just ran some tests and it runs about the same speed as most of the ones in the OP. AdvancedCSharpMessenger was faster than mine, just as it was faster then the rest of them.

    But it just doesn't have the feature set I want. I'm willing to take the small performance hit for the features.

    My point of posting is to highlight that sometimes efficiency isn't the only thing to concern yourself with.
    Last edited: Jun 7, 2014
  25. dkozar

    dkozar

    Member

    Joined:
    Nov 30, 2009
    Messages:
    1,395
    Hi =)

    As for eDriven, you might want to take a look at its GitHub page: https://github.com/dkozar/eDriven

    eDriven uses 2 parallel event systems:

    1. First one is inspired with HTML Dom Level 3 events (similar to Actionscript 3 events)
    2. Signals and Slots (much faster, handy for internal messaging)

    To see them in action, there's a bunch of demos available in the free version of eDriven.Gui.

    Many of this stuff is also explained in this manual:

    http://edriven.dankokozar.com/manual/eDriven_Manual_2-0.pdf

    Cheers!