-
Notifications
You must be signed in to change notification settings - Fork 275
Feature: new asyncio executor #1399
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: rolling
Are you sure you want to change the base?
Conversation
|
I would love to see this make its way into main. My main frustration with rclpy is that it seems to ignore the "Pythonic" way of doing things in favor of its own way. Asyncio integration would make ROS2 much more pleasant to work with in Python. |
|
Mentioning #1461 |
53db751 to
076243c
Compare
2beed28 to
f4590d8
Compare
f4afea4 to
429a60a
Compare
UpdateI worked through a couple of design iterations, and I believe I settled on one that almost exactly matches the behavior of SingleThreadedExecutor. @sloretz you came up in the last working group meeting as the most qualified maintainer to review this PR. |
|
Thank you for the PR!
I'm giving it a skim now, but it might take me a while to review it fully. I think we could take a couple changes right away. Would you be willing to create two PRs and ping me as a reviewer?
One of the reasons |
|
Guard condition and waitable support will be important (Actions are implemented using waitables). Are there any technical blockers to implementing them in the asyncio executor? Callback groups support isn't necessary. Callback groups were created for C++, but the problem they solve in C++ is solved in Python by using coroutines. I don't think we need callback groups in rclpy at all. |
Both coroutines and multi-threading are different methods to achieve concurrency. Without asyncio, the only way to utilize many libraries (serial, HTTP, DB drivers) was multi-threading, but now this is no longer the case.
Asyncio is not thread safe so the AsyncioExecutor isn't either.
Regarding guard conditions, the classic “wake the wait-set from a different thread”
As discussed in one of the working group meetings,
Sounds good. I'll let you know when they're ready. |
|
|
@sloretz friendly ping |
28f61cc to
c05596a
Compare
Signed-off-by: Nadav Elkabets <elnadav12@gmail.com>
c05596a to
e336d83
Compare
Signed-off-by: Nadav Elkabets <elnadav12@gmail.com>
Signed-off-by: Nadav Elkabets <elnadav12@gmail.com>
Signed-off-by: Nadav Elkabets <elnadav12@gmail.com>
Signed-off-by: Nadav Elkabets <elnadav12@gmail.com>
Signed-off-by: Nadav Elkabets <elnadav12@gmail.com>
Signed-off-by: Nadav Elkabets <elnadav12@gmail.com>
Signed-off-by: Nadav Elkabets <elnadav12@gmail.com>
5e2bd35 to
e0e28bb
Compare
Signed-off-by: Nadav Elkabets <elnadav12@gmail.com>
Motivation
While rclpy is task-based and built with asynchronous support, its custom implementation imposes significant limitations and lacks integration with Python's asyncio ecosystem. Integrating rclpy nodes with modern asyncio-based Python libraries like FastAPI and pyserial-asyncio is difficult and often forces developers into complex multi-threaded solutions.
Inspired by @sloretz's PR #971, this PR introduces an asyncio-based executor that runs nodes entirely on the asyncio event loop, which has become the de facto standard for IO programming in the Python community.
Design considerations
C++ vs. Python Implementation
py::exec. In addition, casting the EventsExecutor type to Executor feels to me like unhealthy practice.Callback Handling
asyncio.call_soon_threadsafe. Since most of asyncio’s core is in C, this amounts to grabbing a lock, enqueueing the task, and writing to a wake-fd, which is an extremely lightweight operation.Futures Compatibility
get_loop()and_asyncio_future_blockingapi.loop.create_future(). Asyncio even enforces in runtime that the future belongs to the running loop. In contrast,rclpylets you callclient.call_async()without an executor, which is only set when the response arrives.Spin Behavior
loop.run_forever()or similar asyncio methods.Changes
AsyncioExecutorclass that runs entity events as asyncio tasks on the event loop.Supported & Unsupported Entities
Supported
Not Supported
set_on_ready_callbackapproach of rclcppUpdates
test_rclpy_performance.pyscript from the EventsExecutor PR on the asyncio executor yielded fantastic results!