Search Unity

[Solved] UnityEvent.Invoke() calling order

Discussion in 'UGUI & TextMesh Pro' started by Senshi, Aug 28, 2014.

  1. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    557
    Hi everyone,

    I was just wondering if it's safe to assume any specific calling order for UnityEvent delegates? Taking the following code:

    Code (csharp):
    1. UnityEvent e = new UnityEvent();
    2. e.AddListener(delegate{A();});
    3. e.AddListener(delegate{B();});
    4. e.AddListener(delegate{C();});
    5. e.Invoke();
    Is it safe to assume that the functions will always be executed in the same exact order (A, B, C)?

    Thanks,
    Patrick
     
  2. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    So internally this uses a delegate where call order is not defined. This means you can't rely on the order. Looking at the implementation is SEEMS like it is order dependent, but a mono upgrade of a change in the phase of the moon could break this so please don't rely on it.
     
  3. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    557
    Ah, drats! I was afraid there might be a gotcha there, so glad I asked and thanks for the quick answer as always! =)
     
    ivaylo5ev likes this.
  4. Immanuel-Scholz

    Immanuel-Scholz

    Joined:
    Jun 8, 2013
    Posts:
    221
    Why do you use a (probably multicast) delegate to distribute the event?

    To me, it would be highly preferable to maintain your own list of callbacks and call them "by hand". Here some list of things that just pop up in my mind:

    - You could do have stable ordering as requested by the OP
    - You could catch exceptions of individual handlers and continue with the next one.
    - You could do some profiling hooks between callback calls.
    - You could automatically unregister and not call handlers again if their Delegate.Target property happens to be a "UnityEngine.Object" that became invalid.. (so it reports an error only on the first try and don't spam-until-out-of-memory when some callbacks are called very frequently)

    Ciao, Imi
     
    diego_fm and rakkarage like this.
  5. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,225
    There are advantages an disadvantages to both. Multicast delegates are nice because they are very fast (at a mono level) so that is what we have gone with. Profiling still works with multicast delegates you will get a separate stack entry for each invoked call. We could potentially change it in the future, but we won't be for v1.
     
  6. Immanuel-Scholz

    Immanuel-Scholz

    Joined:
    Jun 8, 2013
    Posts:
    221
    "Multicast delegates are nice because they are very fast (at a mono level)"

    Really?

    I did lots of benchmarks some years ago (we were using Ogre.NET) and it showed absolutely no difference in looping a list and call each Action seperately to calling them in one multicast delegate. (There were very slim differences when you try to add/remove a listener during another listeners callback.)

    Of course, there is quite a difference if you strip apart an existing multicast delegate and call each internal handler via reflection.. but that was not what I suggested. ;)

    Ciao, Imi.
     
  7. JAKJ

    JAKJ

    Joined:
    Aug 17, 2014
    Posts:
    185
    You tried to refute how something performs on one platform by referring to how it performs on another? That's not how this works.
     
  8. Immanuel-Scholz

    Immanuel-Scholz

    Joined:
    Jun 8, 2013
    Posts:
    221
    "You tried to refute how something performs on one platform by referring to how it performs on another? That's not how this works."

    Yes.. if I would have refuted anything, you would be right.

    I was wondering whether Tim C did any real benchmark or just assumed that multicast delegates must be at least as performant as any other self-made solution (which is a very solid assumption, by the way).

    His hint about "potentially change it in the future" seems to me that the current implementation is rather an "we keep it as easy and close as possible to Action, and extend it from there - at least we don't do anything worse."


    Anyway, the topic here was about guarantee of order of callbacks. Unity seems to not really care about whether they should guarantee anything about order of calls ("you can't rely on the order. .. It seems like its order dependend ... but may change..")


    In most of the games and programms I worked on, problems with the order of callbacks came up as a medium to major headache at least half a dozend times during development. Or at least we could solve a problem by solving some orders of callbacks around, especially during setup and shutdown of things (like zone loading, map restarts, savegames etc)

    Most problems come from places, where people thought (or did some quick tests and assumed) that orders are stable, but then it turned out that they got messed around (e.g. after loading savegames, the order of registered listeners changed...)

    As it is now, the UnityEvent does provide exactly one single service on top of a plain Action field: You can drag'n'drop some stuff in the editor. In my opinion, game engines benefit a lot from powerful callback systems and neither UnityEvent nor SendMessage is anything close to provide the set of features that are needed.


    On another note... TimC: What makes you think the order of an C# multicast delegate is not guaranteed? Delegate.Combine guarantees to concat the lists and Delegate.Invoke guarantees to sequential call the list. So if you don't mess around with the invocation list by yourself, the order IS guaranteed by .NET itself. Of course, as I said: If you don't want people to depend on the order, you should clearly state this intention in the documentation. This way you can implement some mean stuff later that might be potentionally some nano-seconds faster in some places :p. At the cost of usability of UnityEvent... ;)


    PPS: Just looked into Mono source code. They combine delegates by a linked lists iteration and invoke by stack-calling from a backpointer. So for whats worth it: Don't use UnityEvent with very large number of callback registrations or you might run into stack overflows and degrading performance of Add/Removes.
     
    Last edited: Aug 30, 2014
    Senshi likes this.
  9. vlab22

    vlab22

    Joined:
    Nov 22, 2012
    Posts:
    17