-
Notifications
You must be signed in to change notification settings - Fork 61
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
agent with events #852
base: main
Are you sure you want to change the base?
agent with events #852
Conversation
mock ros2 environment with mock chitchat
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review from point view of multi-threading implementation:
I.
If I understood correctly new thread is created inside
AgentObject.__metta_call
and inside
EventObject.start
Does it mean that a separate thread is created for each event (and for each _metta_call of object)? If yes, then it might be relatively expensive for some particular use cases (on my machine creating/destruction of 1000 threads costs ~0.05 sec + some memory footprint). However I'm not ready right now to propose an alternative.
II.
In
EventAgent.event_processor
if self.events is empty the thread will consume 100% CPU by running
while True:
If I understood correctly this code should work, but it will not exit after self.running is set to False. However it should be noted that the current code (code from PR, not what is proposed here) does not guarantee it neither if event_processor can be called from different threads (if two threads pass self.events.empty but only one consume get) .
def event_processor(self, *args):
# `*args` received on `start`
while self.running:
(event_id, func, args) = self.events.get()
# Wrapping into ValueAtom if arg is not an atom yet
with self.lock:
resp = self._metta.evaluate_atom(E(func,
*[a if isinstance(a, Atom) else ValueAtom(a) for a in args]))
for r in resp:
self.outputs.put(r)
(we don't need self.lock at all if self._metta.evaluate_atom is thread safe and we don't care about order inside self.outputs)
If we want that self.events.get() is gracefully (without running in daemon mode for example) terminated immediately after self.running
is set to False
then it is tricky. Possible solution (for proposed version of the code):
- Use timeout in get
- Use "sentinel" object (put termination object in queue), but if there are many threads, we should put as many sentinel objects as there are threads
An addition to my previous comment: In python 3.13 queue has shutdown functionality. So together with setting self.running to false we could simply shutdown queue and handle Shutdown exception. As I've mentioned in previous commend, before python 3.13 the standard solution seems to be a sentinel object trick, by the way I was wrong that we need as many sentinel objects as there are threads, since we can simply put sentinel object back to queue. |
@astroseger , |
No description provided.