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

#30014: refactor poll-related classes #1035

Merged
merged 9 commits into from May 20, 2017
Merged

Conversation

giampaolo
Copy link
Contributor

@giampaolo giampaolo commented Apr 7, 2017

Refactor poll-related classes so that poll(), epoll() and devpoll() share the same methods for register(), unregister(), close() and select().
This was inspired by http://bugs.python.org/issue30014 and serves as a strategy to avoid duplicating the implementation of modify() method.

UPDATE 2017-05-20: also use a single self._poller attribute for all classes instead of having self._poll, self._kqueue etc..

@Haypo

…poll() share the same methods for register(), unregister(), close() and select()
Lib/selectors.py Outdated
"""Poll-based selector."""
def __init__(self):
super().__init__()
self._poller = self._poller()
Copy link
Contributor

@cf-natali cf-natali Apr 29, 2017

Choose a reason for hiding this comment

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

This looks strange: I assume that self._poller is the poller class (e.g. select, poll, etc).
It's used here but not defined in this base class: maybe make it an abstract property to force its definition?
Also, assigning
self._poller = self._poller() is very confusing: you're reusing the same member for the instance and the class.
Maybe use poller_cls, or poller_type for the type of the poller, to avoid confusion with the instance?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, the idea is to have a _poller attribute which can be referenced by all 3 classes. Actually I think it'd be cool to do the same also for select and kqueue.
And yes, it's probably better to also have _poller_cls.
I don't have a strong opinion about abstract properties but it's up to you.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How would you feel about having a _selector attribute for all classes (also kqueue and select)?

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds great.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Lib/selectors.py Outdated
poller_events |= self._EVENT_WRITE
try:
self._poller.register(key.fd, poller_events)
except BaseException:
Copy link
Contributor

Choose a reason for hiding this comment

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

I think catching BaseException is discouraged, shouldn't it be Exception?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, I think it should; I think I copied it from the previous code

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Lib/selectors.py Outdated
key = super().unregister(fileobj)
try:
self._poller.unregister(key.fd)
except OSError:
Copy link
Contributor

Choose a reason for hiding this comment

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

Why catch OSError here and BaseException in register()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I copied it from the previous code:

except OSError:

...although the original code did that for epoll only wheres with this it's applied to all 3 selectors. Not sure if it matters. Probably not.
In general I think it would make sense to always catch OSError (also in kqueue).

Copy link
Contributor

@cf-natali cf-natali May 20, 2017

Choose a reason for hiding this comment

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

Agreed, let's catch OSError everywhere.

Lib/selectors.py Outdated
self._devpoll = select.devpoll()
_poller = select.devpoll
_EVENT_READ = select.POLLIN
_EVENT_WRITE = select.POLLOUT

def fileno(self):
return self._devpoll.fileno()
Copy link
Contributor

Choose a reason for hiding this comment

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

This can't work, self._devpoll has been replaced by self._poller.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Fixed.

Lib/selectors.py Outdated
ready.append((key, events & key.events))
return ready
def close(self):
if hasattr(self._poller, "close"):
Copy link
Contributor

Choose a reason for hiding this comment

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

Doing such a hasattr() is a bit naughty: why not instead override close() in EpollSelector and DevPollSelector to close the underlying FD?

If you want to maximize code reuse, maybe we could add a _FDBasedSelector - common to al implementations using a file descriptor - in which you could define close() and fileno()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fine with me.

Copy link
Contributor

Choose a reason for hiding this comment

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

Good.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I overrode close() in EpollSelector and DevPollSelector to close the underlying FD as per your suggestion.

Copy link
Contributor

@cf-natali cf-natali left a comment

Choose a reason for hiding this comment

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

Sorry for the delay, didn't see this message.

With the proposed changes, sounds great!

Copy link
Contributor Author

@giampaolo giampaolo left a comment

Choose a reason for hiding this comment

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

Sorry for the delay, didn't see this message.

No problem. ;-)
OK, I think it's ready.

Lib/selectors.py Outdated
"""Poll-based selector."""
def __init__(self):
super().__init__()
self._poller = self._poller()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

Lib/selectors.py Outdated
poller_events |= self._EVENT_WRITE
try:
self._poller.register(key.fd, poller_events)
except BaseException:
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Lib/selectors.py Outdated
ready.append((key, events & key.events))
return ready
def close(self):
if hasattr(self._poller, "close"):
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I overrode close() in EpollSelector and DevPollSelector to close the underlying FD as per your suggestion.

Lib/selectors.py Outdated
self._devpoll = select.devpoll()
_poller = select.devpoll
_EVENT_READ = select.POLLIN
_EVENT_WRITE = select.POLLOUT

def fileno(self):
return self._devpoll.fileno()
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Fixed.

Copy link
Contributor

@cf-natali cf-natali left a comment

Choose a reason for hiding this comment

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

Great!

@giampaolo giampaolo merged commit 62c7d90 into master May 20, 2017
@giampaolo giampaolo deleted the selectors-refactoring branch May 20, 2017 09:34
@giampaolo
Copy link
Contributor Author

Cool. Merged. I'll submit a PR for a faster modify() soon.

@vstinner
Copy link
Member

vstinner commented May 20, 2017 via email

@giampaolo
Copy link
Contributor Author

Thanks Victor. ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants