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.

Author gvanrossum
Recipients eric.snow, georg.brandl, gvanrossum, neologix, pitrou, python-dev, serhiy.storchaka, vstinner
Date 2014-01-26.18:22:29
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1390760550.28.0.941574026584.issue20311@psf.upfronthosting.co.za>
In-reply-to
Content
AFAICT the changes to selectmodule.c have been rolled back, both in the 3.3 and the 3.4 (default) branches. That takes care of backwards compatibility. :-)

So what we're talking about is whether (a) the selectors module (new in 3.3) should export a resolution property and what asyncio should do.

The selectors module in the repo does export a resolution property. It is 1 usec for select, 1msec for poll and epoll, and 1 nsec for kqueue. AFAIK these values are derived from the data type and scale used by the corresponding syscall.

The latest code in the asyncio module uses that resolution for exactly one purpose: if, after waking up from a selector.select() call, any events we are waiting for are less than the resolution in the future, we consider them ready.

I like this approach -- it trusts the syscall to do approximately the right thing most of the time, but it doesn't fall into the busy-wait trap. This trap is especially egregious for [e]poll, where the timing resolution is limited to 1 msec due to the syscall interface.

To explain the trap once more: suppose you have an event scheduled 0.9 msec in the future. Because of the 1 msec resolution of the [e]poll syscall API, the syscall is made with an argument of 0, which means it returns (almost) immediately. Given a fast CPU and no other IO ready, this might well take only a few usec. So the event loop does essentially nothing and then comes back to the poll call. The same event is now e.g. 0.89 msec in the future. So we call [e]poll with a timeout of 0 again, and we keep going around without ever releasing the CPU for the full 0.9 msec -- which nowadays is serious time in which a lot of other, more useful things could be accomplished by other threads or processes.

I think what's currently in the repo is all a fine solution to all that. Because the resolution is specified on a per-selector-class basis, we compensate appropriately for [e]poll but don't apply such a coarse granularity to the other syscalls, which are (potentially) more accurate.

If in the future we find that on some systems the kernel systematically rounds the timeout down using some coarser clock resolution we can add a system-specific compensation to the selectors module, and asyncio itself doesn't have to worry about it. (Though I personally don't expect we'll find this behavior.)

One final comment: IIUC the earlier fix involved using ceil() and other cleverness was essentially trying to predict *when* the next tick would wake us up, assuming that if the resolution is R, the kernel would wake us up at times that are integral multiples of R since the clock epoch. I don't think we can assume this at all, so I'm glad Victor rolled that back. :-)
History
Date User Action Args
2014-01-26 18:22:30gvanrossumsetrecipients: + gvanrossum, georg.brandl, pitrou, vstinner, neologix, python-dev, eric.snow, serhiy.storchaka
2014-01-26 18:22:30gvanrossumsetmessageid: <1390760550.28.0.941574026584.issue20311@psf.upfronthosting.co.za>
2014-01-26 18:22:30gvanrossumlinkissue20311 messages
2014-01-26 18:22:29gvanrossumcreate