[Python-Dev] PEP 418: Add monotonic clock (original) (raw)

Nick Coghlan ncoghlan at gmail.com
Wed Mar 28 17:35:46 CEST 2012


On Thu, Mar 29, 2012 at 1:02 AM, Yury Selivanov <yselivanov.ml at gmail.com> wrote:

On 2012-03-28, at 10:45 AM, Nick Coghlan wrote:

On Thu, Mar 29, 2012 at 12:27 AM, Yury Selivanov <yselivanov.ml at gmail.com> wrote: What if system time jumps 1 year back?  We'll have the same monotonic time returned for this whole year?

I don't think we should even try to emulate any of OS-level functionality. You have to keep in mind the alternative here: falling back to an unconditioned time.time() value (which is the status quo, and necessary to preserve backwards compatibility). That will break just as badly in that scenario and is precisely the reason that the OS level monotonic functionality is desirable in the first place. Well, my argumentation is that you either have some code that depends on monotonic time and can't work without it, or you have a code that can work with any time (and only precision matters).  Maybe I'm wrong.

You're wrong.

The primary use case for the new time.monotonic() function is to replace existing uses of time.time() in the standard library (mostly related to timeouts) that are currently vulnerable to clock adjustment related bugs. This real, concrete use case has been lost in some of the abstract theoretical discussions that have been going on this thread.

We can't lose sight of the fact that using a system clock that is vulnerable to clock adjustment bugs to handle timeouts and benchmarking in Python has worked just fine for 20+ years. Using a monotonic clock instead is better, but it's far from essential, since clock adjustments that are big enough and poorly timed enough to cause real problems are fortunately a very rare occurrence.

So, the primary use case is that we want to replace many of the time.time() calls in the standard library with time.monotonic() calls. To avoid backwards compatibility problems in the cross-platform support, that means time.monotonic() must be available on every platform that currently provides time.time().

This is why Victor's original proposal was that time.monotonic() simply fall back to time.time() if there was no OS level monotonic clock available. The intended use cases are using time.time() right now and have been doing so for years, so it is clearly an acceptable fallback for those cases. People (rightly, in my opinion) objected to the idea of time.monotonic() failing to guarantee monotonicity, thus the proposal to enforce at least a basic level of monotonicity through caching of the last returned value. I agree completely that this dumb caching solution doesn't solve any of the original problems with time.time() that make a time.monotonic() function desirable, but it isn't meant to. It's only meant to provide graceful degradation to something that is no worse than the current behaviour when using time.time() in Python 3.2 while still respecting the property of monotonicity for the new API. Yes, it's an ugly hack, but it is a necessary fallback to avoid accidental regressions in our cross-platform support.

For the major platforms (i.e. *nix, Mac OS X, Windows), there will be an OS level monotonic clock available, thus using time.monotonic() will have the desired effect of protecting from clocks being adjusted backwards. For other platforms, the behaviour (and vulnerabilities) will be essentially unchanged from the Python 3.2 approach (i.e. using time.time() with no monotonicity guarantees at all).

However, some 3.3+ applications may want to be stricter about their behaviour and either bail out completely or fall back to an unfiltered time.time() call if an OS-level monotonic clock is not available. For those, it makes sense to expose time.os_monotonic() directly (and only if it is available), thus allowing those developers to make up their own mind instead of accepting the cross-platform fallback in time.monotonic().

Yes, you can get the exact same effect with the "monotonic()" and "try_monotonic()" naming scheme, but why force the standard library (and anyone else wanting to upgrade from time.time() without harming cross-platform support) to use such an ugly name when the "os_monotonic" and "monotonic" naming scheme provides a much neater alternative?

Regards, Nick.

-- Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia



More information about the Python-Dev mailing list