-
Notifications
You must be signed in to change notification settings - Fork 23
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
Threaded operation #34
base: main
Are you sure you want to change the base?
Conversation
…s on the queue and an event to stop the thread.
…s on the queue and an event to stop the thread.
…s on the queue and an event to stop the thread.
…s on the queue and an event to stop the thread.
@dmopalmer, I'm sorry, but I am still convinced that asyncio is a better direction for this packaging than threading, because it's so I/O intensive. |
Asyncio is probably a better direction in theory, but threading is available with this pull request in time for the next LIGO-VIRGO-ETC run. This request doesn't affect the core functionality in any major way, and won't prevent asyncio from being implemented later. |
This PR really contains several mostly-separable changes that could be broken into multiple PRs:
Here are my reactions too each of these:
|
So if I
would that be a pull request you are happy with? For eventual |
If 2 will help your application, I would accept it as a self-contained PR.
What is the value of introducing a thread here? The
What is terminate? Python's
I can think of at least two possible styles of async APIs. The first is that the listen method could return an asynchronous iterator suitable for use in an async for loop in the calling program. The second is that the calling program simply passes a handler callback, as it currently does. The callback need not be asynchronous. I have a working asyncio VOEvent Transport Protocol client here: https://github.com/nasa-gcn/gcn-classic-to-kafka/blob/main/gcn_classic_to_kafka/socket.py |
Yeah, it appears that the only way to gracefully terminate a thread is cooperatively, such as by the sentinel method, which requires the socket reads to timeout so the sentinel can be checked. Probably the way forward is to not have any way to stop the thread (apart from program termination). YAGNI. The documentation should suggest using processes instead if killing the listener will be necessary. For 3. the value of introducing a thread is to show the user how to use threads. Probably the extra section in the README is sufficient for that and we can remove threaded_listen_main() altogether. I also wrote that function as a test case for debugging. |
But why is it useful to show the user how to use threads? I do not see how this is any different from placing any other Python code in a thread. Surely users can read the Python standard library documentation on threads. |
The only use in showing the user how to use threads is showing how to use the
That client immediately |
I think you'd just use task cancellation. |
I don't want to cancel the task and then restart it and lose the messages that came in when it was cancelled. My use case, which is probably common, is to have a telescope make observations of yesterday's GRB while keeping a VOEvent socket open to quickly change observations to a new LIGO event coming in. So after each exposure I check the message queue for something more interesting. |
I got back to this in preparation for the LIGO/et al. run. I have stripped out the stopevent capability. The changes consist of a queue handler implementation and a description in the README of how to use it. |
Just re-pinging his pull request. |
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.
I would be content with adding the new handler, but not the threading code sample.
@@ -28,6 +28,7 @@ classifiers = | |||
Programming Language :: Python :: 3.8 | |||
Programming Language :: Python :: 3.9 | |||
Programming Language :: Python :: 3.10 | |||
Programming Language :: Python :: 3.11 |
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.
This is a nice addition, but not related to the topic of this PR.
Programming Language :: Python :: 3.11 |
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.
I don't know why GitHub is showing this in the diff. It's already on the main branch, as of #35. Would you please rebase?
queue.put((payload, root)) | ||
|
||
|
||
def queuehandlerfor(queue): |
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.
The other handlers have function names that are verbs or verb phrases. Please rename this one to be consistent. Perhaps 'enqueueor
put_queue`?
## Threading | ||
|
||
You can run the listener in a separate thread or process and pass the packets back in a `Queue`, | ||
allowing the main program to continue operating while waiting for an event. | ||
Here is an example: | ||
|
||
```python | ||
#!/usr/bin/env python | ||
import gcn | ||
import threading | ||
import queue | ||
|
||
# Set up communications: | ||
messagequeue = queue.Queue() | ||
# Create a listen handler to enqueue the (payload, root) tuple | ||
handler = gcn.handlers.queuehandlerfor(messagequeue) | ||
|
||
# Create and start the thread. | ||
thread = threading.Thread(target=gcn.listen, | ||
kwargs=dict(handler=handler)) | ||
thread.start() | ||
|
||
# Wait for messages to come in, but do other things if they don't. | ||
nothingcount=0 | ||
while True: | ||
try: | ||
# Use block=False if you want to timeout immediately | ||
payload,root = messagequeue.get(timeout=10) | ||
print(root.attrib['ivorn']) | ||
nothingcount = 0 | ||
except queue.Empty: | ||
# Do idle stuff here. | ||
print("Nothing...") | ||
nothingcount += 1 | ||
if nothingcount > 10: | ||
print("Quitting due to inactivity") | ||
break | ||
``` | ||
|
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.
Please remove this. If someone asked how to run the listener in a thread, this isn't how I would suggest to them that they do it. (I would suggest to them that they use an ordinary handler and just launch gcn.listen
in a thread or a subprocess.)
Also, this is missing calls to queue.task_done()
.
FYI, passing the lxml |
This is a renewal of an old pull request. (Previously not accepted because @lpsinger intended to implement
async
instead of threading.)This supports threaded operation by providing a handler that queues messages.