/Relay

Fast, powerful, GC-friendly C# signals/events for Unity.

Primary LanguageC#MIT LicenseMIT

Relay

Fast, light, GC-friendly C# signals/events for Unity.


C# event multicasting is a nice language-level feature, but in Unity's version of Mono, events allocate a lot on addition/removal and aren't always easy to manipulate. Relay aims to address these issues.

  • Additional functionality
    • AddOnce() automatically removes a listener after dispatch
    • Guard against duplicate listeners for safety, or disable checking for increased performance
    • Contains() tells you whether a delegate is already subscribed
    • Debug mode helps diagnose "dangling" or "lapsed" listeners - a common cause of GC issues in event-driven architectures
  • Minimal allocation using arrays of delegates
    • C# event re-allocates the entire multicast object each time += or -= called
    • Relay uses a dynamic array of singlecast delegates
  • Performant addition, removal and dispatch
    • Geometric array resize (like List<>.Add()) amortizes addition costs
    • Dispatch virtually as fast as native multicast
  • Battle-tested
    • Heavily used in core code of our game Sublevel Zero on PC, VR, PS4 and Xbox One
    • ~100% unit test coverage (unit tests included)

Read the wiki for detailed instructions.

Relay is inspired by the Signals implementation in StrangeIoC (but drastically improves performance and allocation).

Performance (Tested in Unity 5.6)

Profiled performance comparison of event, Relay and a List of delegates. Each operation is performed 100000 times with 10 listeners. Add Unique means disallowing duplicate listeners.

Time (ms)

Method Add Add Unique Remove Clear Dispatch
event 1465 N/A 1155 3.688 67.28
Relay 150.5 318.2 270.0 10.27 79.92
List 183.5 466.0 368.0 9.436 79.00

GC Alloc (MB)

Method Add Remove
event 630 530
Relay 38.1 0
List 32.8 0

All other operations are allocation-free. Note that this is worst-case GC performance for Relay (and List) as each loop creates a completely new Relay. Populating and clearing the same Relay 100000 times just allocates 400B initially, while event still allocates 630MB.

Note: Under .NET 4.6 event addition and removal is 2-7x faster than under Unity.

Perf tests and unit tests are included in Relay/Editor.