[Python-ideas] libuv based eventloop for tulip experiment

Guido van Rossum guido at python.org
Tue Jan 29 19:48:49 CET 2013


On Mon, Jan 28, 2013 at 2:48 PM, Saúl Ibarra Corretgé <saghul at gmail.com> wrote:
> Hi all!
>
> I haven't been able to keep up with all the tulip development on the mailing
> list (hopefully I will now!) so please excuse me if something I mention has
> already been discussed.

Me neither! :-) Libuv has been brought up before, though I haven't
looked at it in detail. I think you're bringing up good stuff.

> For those who may not know it, libuv is the platform layer library for
> nodejs, which implements a uniform interface on top of epoll, kqueue, event
> ports and iocp. I wrote Python bindings [1] for it a while ago, and I was
> very excited to see Tulip, so I thought I'd give this a try.

Great to hear!

> Here [2] is the source code, along with some notes I took during the
> implementation.

Hm... I see you just copied all of tulip and then hacked on it for a
while. :-) I wonder if you could refactor things so that an app would
be able to dynamically choose between tulip's and rose's event loop
using tulip's EventLoopPolicy machinery? The app could just
instantiate tulip.unix_eventloop._UnixEventLoop() (yes, this should
really be renamed!) or rose.uv.EventLoop, but all its imports should
come from tulip.

Also, there's a refactoring of the event loop classes underway in
tulip's iocp branch -- this adds IOCP support on Windows.

> I know that the idea is not to re-implement the PEP itself but for people to
> create different EventLoop implementations. On rose I bundled tulip just to
> make a single package I could play with easily, once tulip makes it to the
> stdlib only the EventLoop will remain.

It will be a long time before tulip makes it into the stdlib -- but
for easy experimentation it should be possible for apps to choose
between tulip and rose without having to change all their tulip
imports to rose imports.

> Here are some thoughts (in no particular order):
>
> - add_connector / remove_connector seem to be related to Windows, but being
> exposed like that feels a bit like leaking an implementation detail. I guess
> there was no way around it.

They would only be needed if we ever were to support WSAPoll() on
Windows, but I'm pretty much decided against that (need to check with
Richard Oudkerk once more). Then we can kill add_connector and
remove_connector.

> - libuv implements a type of handle (Poll) which provides level-triggered
> file descriptor polling which also works on Windows, while being highly
> performant. It uses something called AFD Polling apparently, which is only
> available on Windows >= Vista, and a select thread on XP. I'm no Windows
> expert, but thanks to this the API is consistent across all platforms, which
> is nice. mAybe it's worth investigating? [3]

Again that's probably for Richard to look into. I have no idea how it
relates to IOCP.

> - The transport abstraction seems quite tight to socket objects.

I'm confused to hear you say this, since the APIs for transports and
protocols are one of the few places of PEP 3156 where sockets are
*not* explicitly mentioned. (Though they are used in the
implementations, but I am envisioning alternate implementations that
don't use sockets.)

> pyuv
> provides a TCP and UDP handles, which provide a completion-style API and use
> a better approach than Poll handles.

So it implements TCP and UDP without socket objects? I actually like
this, because it validates my decision to keep socket objects out of
the transport/protocol APIs. (Note that PEP 3156 and Tulip currently
don't support UDP; it will require a somewhat different API between
transports and protocols.)

> They should give better performance
> since EINTR in handled internally and there are less roundtrips between
> Python-land and C-land.

Why would EINTR handling be important? That should occur almost never.
Or did you mean EAGAIN?

> Was it ever considered to provide some sort of
> abstraction so that transports can be used on top of something other than
> regular sockets? For example I see no way to get the remote party from the
> transport, without checking the underlying socket.

This we are considering in another thread -- there are in fact two
proposals on the table, one to add transport methods get_name() and
get_peer(), which should return (host, port) pairs if possible, or
None if the transport is not talking to an IP connection (or there are
too many layers in between to dig out that information). The other
proposal is a more generic API to get info out of the transport, e.g.
get_extra_info("name") and get_extra_info("peer"), which can be more
easily extended (without changing the PEP) to support other things,
e.g. certificate info if the transport implements SSL.

> Thanks for reading this far and keep up the good work.

Thanks for looking at this and reimplementing PEP 3156 on top of
libuv! This is exactly the kind of thing I am hoping for.

> Regards,
>
> [1]: https://github.com/saghul/pyuv
> [2]: https://github.com/saghul/rose
> [3]: https://github.com/joyent/libuv/blob/master/src/win/poll.c
>
> --
> Saúl Ibarra Corretgé
> http://saghul.net/blog | http://about.me/saghul

-- 
--Guido van Rossum (python.org/~guido)



More information about the Python-ideas mailing list