This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: selectors: refactor BaseSelector implementation
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 3.4
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: Nosy List: eric.araujo, giampaolo.rodola, gvanrossum, martin.panter, neologix, pitrou, python-dev, vstinner
Priority: normal Keywords: needs review, patch

Created on 2013-11-30 13:44 by neologix, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
selectors_base_impl.diff neologix, 2013-11-30 13:44 review
Messages (16)
msg204809 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-11-30 13:44
Initially, BaseSelector was simply designed as the base implementation used by concrete ones like SelectSelector & Co.

Then BaseSelector evolved to be an ABC, but the problem is that it's really not usable as such: the register() and unregister() methods are not abstract, and instead store the fileobj -> key association in a private dictionary (_fd_to_key). Since this attribute is private, it cannot be used by third-party selectors implementation which might want to implement the ABC. Also, such implementations might not want to use a dictionay internally, and generally, inheritance should be avoided in this type of situations (since it breaks encapsulation).

In short, BaseSelector mixes up the type definition (ABC) and base implementation, which cannot be reused by subclasses anyway.

The attached patch cleans things up by making BaseSelector.{register,unregister,get_map} methods abstract (raising NotImplementedError by default).
Together with select(), those methods are the bare minimum that a conform selector implementation should provide.
get_key() still has a default implementation (atop get_map()), and so does modify() (atop register()/unregister()).

The concrete base implementation (on top of which are built SelectSelector & friends) is moved in a private _BaseSelectorImpl.

I think that's a cleaner design.

The only problem is that it makes some methods abstract, so I had to update test_telnetlib and asyncio/test_utils because they are implementing BaseSelector for mock tests.

BTW, is there a consensus on ABC names? Like AbstractSelector vs BaseSelector?
msg204812 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-11-30 14:09
I'm wondering, is there a reason we made BaseSelector a public API?
msg204817 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-11-30 15:14
> I'm wondering, is there a reason we made BaseSelector a public API?

The idead was to have an ABC so that users can implement their own
selector, and pass it to e.g. asyncio or anything alse expecting a
selector.
Other than that, the only use is as a documentation (i.e. to show
which methods are supported by all selectors implementations).
msg204819 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-11-30 15:17
> The idead was to have an ABC so that users can implement their own
> selector, and pass it to e.g. asyncio or anything alse expecting a
> selector.
> Other than that, the only use is as a documentation (i.e. to show
> which methods are supported by all selectors implementations).

The problem for documentation use is that we're christening it as an
official API, and thus it becomes more difficult to refactor the
inheritance hierarchy.
msg204820 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-11-30 15:23
> The problem for documentation use is that we're christening it as an
> official API, and thus it becomes more difficult to refactor the
> inheritance hierarchy.

So what would you suggest?
msg204821 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2013-11-30 15:28
> > The problem for documentation use is that we're christening it as an
> > official API, and thus it becomes more difficult to refactor the
> > inheritance hierarchy.
> 
> So what would you suggest?

Hmmm... Well I guess your proposal makes sense :-) Aka. having a
documented ABC, and then a private base implementation.

Otherwise, you can also document the methods without saying precisely to
which class they belong, which I started doing on asyncio, but
apparently it confuses some people.
msg204861 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2013-11-30 23:45
LGTM, although I wish that you had time to implement the comment "TODO: Subclasses can probably optimize this even further" rather than just shuffling the existing code around. :-)
msg204888 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-12-01 07:59
> Guido van Rossum added the comment:
>
> LGTM, although I wish that you had time to implement the comment "TODO: Subclasses can probably optimize this even further" rather than just shuffling the existing code around. :-)

I will look a this, but I rather take care of the API than
implementation details :-)
Also, I'm not sure that modify() is actually a performance-critical
code-path: do you have any semi-realistic asyncio-based benchmark I
could use?
msg204895 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2013-12-01 09:35
> I think that's a cleaner design.

For common containers like Sequence or Mapping, ABC are useful. But I don't expect new implementations of BaseSelector. Is it just for purity? :-p
msg204896 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2013-12-01 09:36
(I'm not opposed to the change, I'm just asking.)
msg204898 - (view) Author: Giampaolo Rodola' (giampaolo.rodola) * (Python committer) Date: 2013-12-01 09:43
In those protocols where client and server exchange a lot of commands and responses in a single session, such as FTP, modify() is going to be called many times.
I don't have actual numbers but I remember that using epoll.modify() was one of those relatively small optimizations which all put together led to current pyftpdlib performances. For poll() and epoll() pollers I see no reason not to use the specialized modify().

That aside, what actually *does* make a big difference and it is very important is to "unregister" a fd for writing (EVENT_WRITE) when there's no more data to send, and that's something that should be done at a higher level (transport.write() and anywhere else some data is sent).
msg204901 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2013-12-01 10:04
New changeset f48f302f54aa by Charles-François Natali in branch 'default':
Issue #19842: Refactor BaseSelector to make it an actual usable ABC.
http://hg.python.org/cpython/rev/f48f302f54aa
msg204902 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2013-12-01 10:12
> STINNER Victor added the comment:
>
>> I think that's a cleaner design.
>
> For common containers like Sequence or Mapping, ABC are useful. But I don't expect new implementations of BaseSelector. Is it just for purity? :-p

There are already implementations in the test suite, but the main
reason is for documentation purposes (i.e. to document clearly which
methods are available, and which are optional).
IMO, ABC make documentation more clear, and also make it easier for
third-party implementations.

I don't have a strong opinion on this, my real concern is really just
the documentation, so if you can propose a documentation patch that
makes things clear, I'm perfectly fine with removing BaseSelector from
the API :-)
msg205325 - (view) Author: Éric Araujo (eric.araujo) * (Python committer) Date: 2013-12-05 22:32
Do I understand right that BaseSelector.register means something else entirely than ABC.register?  Is it a concern?
msg205327 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2013-12-05 22:39
Well, registration is a very common pattern and you can't really require everyone to use an inferior word just because ABCMeta uses it.

There's a simple work-around:

abc.ABCMeta.register(selectors.BaseSelector, C)
msg205381 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2013-12-06 15:57
This is done AFAICT.
History
Date User Action Args
2022-04-11 14:57:54adminsetgithub: 64041
2013-12-06 15:57:13gvanrossumsetstatus: open -> closed
resolution: fixed
messages: + msg205381

stage: patch review -> resolved
2013-12-06 13:44:41martin.pantersetnosy: + martin.panter
2013-12-05 22:39:36gvanrossumsetmessages: + msg205327
2013-12-05 22:32:49eric.araujosetnosy: + eric.araujo
messages: + msg205325
2013-12-01 10:12:49neologixsetmessages: + msg204902
2013-12-01 10:04:59python-devsetnosy: + python-dev
messages: + msg204901
2013-12-01 09:43:12giampaolo.rodolasetmessages: + msg204898
2013-12-01 09:36:45vstinnersetmessages: + msg204896
2013-12-01 09:35:35vstinnersetnosy: + vstinner
messages: + msg204895
2013-12-01 07:59:59neologixsetmessages: + msg204888
2013-11-30 23:45:12gvanrossumsetmessages: + msg204861
2013-11-30 15:43:44giampaolo.rodolasetnosy: + giampaolo.rodola
2013-11-30 15:28:05pitrousetmessages: + msg204821
2013-11-30 15:23:24neologixsetmessages: + msg204820
2013-11-30 15:17:19pitrousetmessages: + msg204819
2013-11-30 15:14:20neologixsetmessages: + msg204817
2013-11-30 14:09:49pitrousetmessages: + msg204812
2013-11-30 13:44:36neologixcreate