# The ROS 2 C++ Executors

**URL:** <https://discourse.openrobotics.org/t/the-ros-2-c-executors/38296>\
**Category:** ROS General\
**Tags:** ros2, rclcpp, wg-client-libraries\
**Created:** [June 22, 2024, 6:08pm UTC](https://discourse.openrobotics.org/t/the-ros-2-c-executors/38296 "2024-06-22T18:08:04Z")\
**Posts on this page:** 1\
**Showing post:** 4

<div class="post-metadata">

**Author:** ![alsora](https://sea2.discourse-cdn.com/flex022/user_avatar/discourse.openrobotics.org/alsora/32/2514_2.png) [@alsora](https://discourse.openrobotics.org/u/alsora)\
**Post date:** [June 24, 2024, 12:40am UTC](https://discourse.openrobotics.org/t/the-ros-2-c-executors/38296/4 "2024-06-24T00:40:23Z")

</div>

TL;DR;  
before making the `EventsExecutor` the default one we need to fix a bug and provide an alternative, backward compatible, mode.

* * *

The long version:

> [@smac](#):
>
> Are there any notable downsides to the EventsExecutor current implementation we should be aware of or where it is not feature complete?

There’s currently an important bug that makes the events-executor not usable in combination with simulated time: [TimersManager doesn't follow ROS time · Issue #2480 · ros2/rclcpp · GitHub](https://github.com/ros2/rclcpp/issues/2480)  
The client library working group is currently discussing solutions.

> [@facontidavide](#):
>
> Shall we consider changing the default executor in the tutorial to the `EventsExecutor`?

Besides the aforementioned bug, there are some concerns that the current implementation of the events-executor has a different ordering for entities execution with respect to the other executors.  
This concept applies to situations when an executor thread awakes and there’s more than 1 entity ready for work.

The `EventsExecutor` always executes entities in the order in which they become ready, while wait-set based executors have a fixed order: they always execute timers first, then subscriptions, etc; moreover there’s an implicit ordering also within each group of entities, based on the order in which entities were added to the executor or node.

Note that this contributes to the difference in performance: wait-set based executors iterate over list of entities and check which one is ready. If you have 50 entities in an executor, but only 1 is receiving messages, you will waste time looping every time (that’s why disabling builtin services/topics improves CPU with wait-set executors).  
With the events-executor on the other hand you have a list of ready events each with an associated entity, so every time the executor has work to do, rather than iterating over multiple lists you will have look-ups in a map.

This difference affects also the situation where an entity has more than one item of work to do, such as a subscription that received 2 messages.  
The wait-set based executors can’t process 2 items of work from the same entity within the same iteration.  
So the `SingleThreadedExecutor` in this situation will 1) loop through everything and execute the first message, 2) try to go back to sleep 3) wake up immediately and 4) loop through everything again and execute the second message.  
On the other hand, whenever the `EventsExecutor` wakes up, it will execute all the available events before going back to sleep.

IMO the `EventsExecutor` approach besides being way more performant, is also more correct, as it ensures that all events will be processed as soon as possible.  
However, before making the `EventsExecutor` default, it was requested that we provided an alternative implementation that ensures the same ordering behavior as other executors.

The `EventsExecutor` design allows to support different behaviors through the definition of custom `EventQueue` class.  
The current implementation in `rclcpp` just [uses a `std::queue` under the hood](https://github.com/ros2/rclcpp/blob/rolling/rclcpp/include/rclcpp/experimental/executors/events_executor/simple_events_queue.hpp#L121-L127), so the idea is to write a new class that internally will sort events as is done by wait-set executors.  
This will obviously come at a performance cost (I expect performance to still be a lot better than the current default executor), but users can always switch to different queue implementations.  
P.S. There are already other queue implementations in the community:

- [iRobot lock free queue implementation](https://github.com/irobot-ros/events-executor/blob/main/irobot_lock_free_events_queue/include/irobot_lock_free_events_queue/lock_free_events_queue.hpp#L92) which for large systems yields even better performance
- [A queue with user-specified priorities](https://github.com/ros2/rclcpp/pull/2412)
- Some discussions about a callback-group-centric executors implemented on top of the `EventsExecutor`.

---

_[View the full topic](https://discourse.openrobotics.org/t/the-ros-2-c-executors/38296)._
