Skip to content
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

PR: Don't block on exit #651

Merged
merged 9 commits into from
May 30, 2021
Merged

PR: Don't block on exit #651

merged 9 commits into from
May 30, 2021

Conversation

impact27
Copy link
Contributor

If the code tries to exit while calling self.poller.poll, the app will freeze until until_dead seconds have elapsed. This avoids that outcome.

If the code tries to exit while calling `self.poller.poll`, the app will freeze until `until_dead` seconds have elapsed. This avoids that outcome.
@@ -121,7 +121,7 @@ def _poll(self, start_time: float) -> t.List[t.Any]:
events = []
while True:
try:
events = self.poller.poll(int(1000 * until_dead))
events = self.poller.poll(1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it mean we are going to iterate every milllisecond?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well a bit longer than that because of the overhead, the time could be adjusted. How does 100ms sounds?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, I don't think the loop is necessary at all. I removed it.

@@ -114,30 +114,18 @@ def _poll(self, start_time: float) -> t.List[t.Any]:
will be an empty list if no messages arrived before the timeout,
or the event tuple if there is a message to receive.
"""
# Check if an event is waiting
events = self.poller.poll(0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it ensure we poll at least once?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand http://api.zeromq.org/2-1:zmq-poll correctly:

If none of the requested events have occurred on any zmq_pollitem_t item, zmq_poll() shall wait timeout microseconds for an event to occur on any of the requested items. If the value of timeout is 0, zmq_poll() shall return immediately. If the value of timeout is -1, zmq_poll() shall block indefinitely until a requested event has occurred on at least one zmq_pollitem_t. The resolution of timeout is 1 millisecond.

A timeout of 0 means that if a message is already there it will be polled.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A timeout of 0 means that if a message is already there it will be polled.

Thanks, although pyzmq doesn't mention that.


# Wait until timeout
until_dead = self.time_to_dead - (time.time() - start_time)
# ensure poll at least once
until_dead = max(until_dead, 1e-3)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the point of waiting at least one millisecond?

@davidbrochart
Copy link
Member

I think that with your changes, this is not needed anymore:
https://github.com/jupyter/jupyter_client/blob/master/jupyter_client/channels.py#L171-L174

# Check if an event is waiting
events = self.poller.poll(0)
if events:
return events
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should check if we have an event at the beginning, we should only wait until_dead and then check.

@impact27
Copy link
Contributor Author

@davidbrochart I applied your comments.

Comment on lines 146 to 148
ready = self._poll()
if ready:
self._beating = True
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
ready = self._poll()
if ready:
self._beating = True
# Wait until timeout
self._exit.wait(self.time_to_dead)
# poll(0) means return immediately (see http://api.zeromq.org/2-1:zmq-poll)
self._beating = bool(self.poller.poll(0))
if self._beating:

continue
else:
elif not self._exit.is_set():
# nothing was received within the time limit, signal heart failure
self._beating = False
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self._beating = False

@@ -107,38 +105,20 @@ def _create_socket(self) -> None:

self.poller.register(self.socket, zmq.POLLIN)

def _poll(self, start_time: float) -> t.List[t.Any]:
def _poll(self) -> t.List[t.Any]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need the _poll() method anymore.

Copy link
Member

@davidbrochart davidbrochart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks a lot for your efforts and patience!

@davidbrochart davidbrochart merged commit 955cc55 into jupyter:master May 30, 2021
@blink1073 blink1073 added this to the 7.0 milestone Jul 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants