1
\$\begingroup\$

I am wondering, aren´t messaging systems slowing the speed of engines down? I mean, lets say that I want to zoom in my camera, without messaging I would do something like:

_camera->zoomIn(0.005f);

But with messaging, I have to broadcast the message (to the bus for example)

Data data;
data.float = 0.005f;
MessageBus::sendMessage(CAMERA_ZOOM_IN,&data);

Then iterate through all systems (all systems that can possibly handle the message) and at the end, when it arrives to my camera system, I have a handling function that calls proper method based on the message type.

eventFunctions[CAMERA_ZOOM_IN](data);

That means it needs some additional time to "do stuff" and also harder implementation. (imagine for different data types I also need some static casts etc.)

So, will it affect the actual speed of my engine?

\$\endgroup\$
1
  • \$\begingroup\$ Yeah it will with around 2-3 nanoseconds. Try to look for what could actually slow down your engine, and don't optimize prematurely. \$\endgroup\$
    – Bálint
    May 27, 2017 at 12:44

2 Answers 2

4
\$\begingroup\$

This is the line that's the crux of your question "Then iterate through all systems (all systems that can possibly handle the message)".

In reality, it depends how you register your listeners.

If you have few, or worse, only have one event type, then yes, you would be looping through most all systems. But that's the point; you don't want your systems to register to the EventSystem for any event; this would force each system to decide for themselves if they'll handle it.

All events a system registers for are ideally events that they have to handle. If that's the case, you're iterating over exactly those systems which need to be notified anyway- event system or not. If you find that that's not the case, your events may not be granular enough (see below).


So how does having multiple event types help?

Say you allow for CameraEvents in your EventSystem.

If you have a system that wants to subscribe to CameraEvents, it would do so by registering with your EventSystem and saying that it's subscribing to CameraEvents; your EventSystem would store the system (or more likely just it's update call) in a list of listeners for specifically CameraEvents.

camEventListeners:List<IListener<CameraEvent>>

When an object broadcasts a CameraEvent, the EventSystem would only loop through all the camEventListeners, not all listeners of all types. Essentially, only those listeners who would need to handle a CameraEvent would be notified.


If you find that you have a lot of systems that are registering for events and then checking certain event parameters to decide whether they handle or ignore those events, your events may not be granular enough.

Imagine you have systems that only care about when a camera zooms but not when a camera pans. Clearly listening for a CameraEvent would make for a bunch of useless calls if you have a lot of these systems that only care about zooming. In this case you may decide to break up your CameraEvent into a CameraZoomEvent and CameraPanEvent and reorganize your systems to broadcast and/or listen to these more specific events.

In this scenario, your EventSystem would then have multiple lists of listeners: one for CameraZoomEvent listeners and one for CameraPanEvent listeners. This can be implemented as a map in your EventSystem.

listenerMap:Map<EventType, List<IListener<EventType>>>

When a new listener is registered, the EventMap adds it to the correct list:

function registerListener(eventType, listener){
    listenerMap.get(eventType).push(listener);
}

When a new event comes in, the EventMap grabs the list for that EventType and updates all the elements in that list.

function broadcastEvent(event){
    // You could either use your programming language's built in type
    // checker or pass in the eventType as a parameter into the broadcast event function.
    for( listener in listenerMap.get(Type.typeof(event))){
        listener.update(event);
    }
}
\$\endgroup\$
6
  • \$\begingroup\$ So basically you mean that I should make a container for each type of Event? Actually now I am representing each event type as an enumaration(so basically they are 1 type). And if i added additional information, for examplte split CameraEvent into ZoomEvent and PanEvent then i would still need to check it, if its interested in this kind of event or not? \$\endgroup\$
    – Pins
    May 27, 2017 at 13:09
  • 1
    \$\begingroup\$ You do not want one event type and do want multiple. You don't need to check anything because your EventSystem has already registered systems to the specific list of events they're interested in. You subscribe a system using something like eventSystem.subscribe(system, eventType). The EventSystem then stores the system in a specific EventType listener list. Then when the an EventType is broadcast, the EventSystem uses the list of listeners for only that EventType- loops through only those systems, and calls their update. I've added an implementation example in my answer. \$\endgroup\$ May 27, 2017 at 13:11
  • \$\begingroup\$ I am scared of the memory usage, or it doesn´t matter? I mean, let´s say that in future, it will have hundreds(thousands - lets call the size X) of event types, does it mean that i will have created X number of lists? \$\endgroup\$
    – Pins
    May 27, 2017 at 13:21
  • \$\begingroup\$ You're overthinking it. You are never going to have thousands of event types. Those events that have multiple variants would have parameters as part of them. Say CollisionEvent(entityA,entityB); your collision system would subscribe to CollisionEvent's and handle the associated parameters. You will never have more event types than the amount that you'd need to have handled anyway in any system. IE. if you have X number of lists, all of the listeners in each of those lists need to receive their updates by design; you're not creating empty lists. \$\endgroup\$ May 27, 2017 at 13:25
  • 1
    \$\begingroup\$ One other thing worth noting is that a message queue can offer a lot of flexibility in when the work happens. If you have a tight inner loop that occasionally generates action items for another system to process, calling into that system directly can thrash the CPU caches, versus just making a note to call it later and continuing speeding through this inner loop. You can also filter those messages to skip ones that were invalidated by events that happened later, and enforce a clear dependency order on which messages get handled when in your frame, simplifying cross-system dependencies \$\endgroup\$
    – DMGregory
    May 27, 2017 at 15:12
2
\$\begingroup\$

It depends on what you use it for, and you're right, you'd have to iterate all systems that could possibly make use of the message.

The overhead is: messages_sent * possible_receivers * handling_overhead

A system like this will slow to a crawl if you distribute, for example, low level AI messages from AI agent to AI agent because the above equation will grow exponentially with the amount of agents. For talking to the camera or triggering an story event it's ok though since the amount of messages and receivers is very limited and controlled by the developer.

Message systems have their place, you don't always want to make variables/objects global or overload constructors beyond good and evil etc.

it can be very tidy and light, if used where there is an actual use case for it.

\$\endgroup\$
2
  • \$\begingroup\$ The overhead is what I am afraid of, if I imagine situation in fully loaded game, lot of messages for engine, lot of messages for game logic(also AI etc.). Thats why I am thinking about if its still worth it. \$\endgroup\$
    – Pins
    May 27, 2017 at 13:10
  • 1
    \$\begingroup\$ You don't have to worry about overhead in that sense, the overhead per message is negligible. What you should think about is whether a message system benefits your engines structure. Optimization can always be done later. \$\endgroup\$
    – VaTTeRGeR
    Jun 17, 2017 at 19:48

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .