Skip to content

#30014: refactor poll-related classes#1035

Merged
giampaolo merged 9 commits into
masterfrom
selectors-refactoring
May 20, 2017
Merged

#30014: refactor poll-related classes#1035
giampaolo merged 9 commits into
masterfrom
selectors-refactoring

Conversation

@giampaolo

@giampaolo giampaolo commented Apr 7, 2017

Copy link
Copy Markdown
Contributor

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()
Comment thread Lib/selectors.py Outdated
"""Poll-based selector."""
def __init__(self):
super().__init__()
self._poller = self._poller()

@cf-natali cf-natali Apr 29, 2017

Copy link
Copy Markdown
Contributor

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

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

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment thread Lib/selectors.py
key = super().unregister(fileobj)
try:
self._poller.unregister(key.fd)
except OSError:

Copy link
Copy Markdown
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
Copy Markdown
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).

@cf-natali cf-natali May 20, 2017

Copy link
Copy Markdown
Contributor

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.

Comment thread Lib/selectors.py Outdated
_EVENT_WRITE = select.POLLOUT

def fileno(self):
return self._devpoll.fileno()

Copy link
Copy Markdown
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
Copy Markdown
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.

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

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good.

Copy link
Copy Markdown
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.

@cf-natali cf-natali left a comment

Copy link
Copy Markdown
Contributor

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!

@giampaolo giampaolo left a comment

Copy link
Copy Markdown
Contributor Author

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.

Comment thread Lib/selectors.py Outdated
"""Poll-based selector."""
def __init__(self):
super().__init__()
self._poller = self._poller()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

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

Copy link
Copy Markdown
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.

Comment thread Lib/selectors.py Outdated
_EVENT_WRITE = select.POLLOUT

def fileno(self):
return self._devpoll.fileno()

Copy link
Copy Markdown
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.

@cf-natali cf-natali left a comment

Copy link
Copy Markdown
Contributor

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
Copy Markdown
Contributor Author

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

@vstinner

vstinner commented May 20, 2017 via email

Copy link
Copy Markdown
Member

@giampaolo

Copy link
Copy Markdown
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.

4 participants