[Python-Dev] PEP 418: Add monotonic clock

Nick Coghlan ncoghlan at gmail.com
Wed Mar 28 17:08:50 CEST 2012


On Thu, Mar 29, 2012 at 12:42 AM, Guido van Rossum <guido at python.org> wrote:
> As I said, I think the caching idea is bad. We may have to settle for
> semantics that are less than perfect -- presumably if you are doing
> benchmarking you just have to throw away a bad result that happened to
> be affected by a clock anomaly, and if you are using timeouts, retries
> are already part of life.

I agree caching doesn't solve the problems that are solved by an OS
level monotonic clock, but falling back to an unmodifided time.time()
result instead doesn't solve those problems either. Falling back to
time.time() just gives you the status quo: time may jump forwards or
backwards by an arbitrary amount between any two calls. Cached
monotonicity just changes the anomalous modes to be time jumping
forwards, or time standing still for an extended period of time. The
only thing the caching provides is that it becomes a reasonable
fallback for a function called time.monotonic() - it *is* a monotonic
clock that meets the formal contract of the function, it's just
nowhere near as good or effective as one the OS can provide.

Forward jumping anomalies aren't as harmful, are very hard to detect
in the first place and behave the same regardless of the presence of
caching, so the interesting case to look at is the difference in
failure modes when the system clock jumps backwards.

For benchmarking, a caching clock will produce a zero result instead
of a negative result. Zeros aren't quite as obviously broken as
negative numbers when benchmarking, but they're still sufficiently
suspicious that most benchmarking activities will flag them as
anomalous. If the jump back was sufficiently small that the subsequent
call still produces a higher value than the original call, then
behaviour reverts to being identical.

For timeouts, setting the clock back means your operation will take
longer to time out than you expected. This problem will occur
regardless of whether you were using cached monotonicity (such that
time stands still) or the system clock (such that time actually goes
backwards). In either case, your deadline will never be reached until
the backwards jump has been cancelled out by the subsequent passage of
time.

I want the standard library to be able to replace its time.time()
calls with time.monotonic(). The only way we can do that without
breaking cross-platform compatibility is if time.monotonic() is
guaranteed to exist, even when the platform only provides time.time().
A dumb caching fallback implementation based on time.time() is the
easiest way to achieve that withou making a complete mockery of the
"monotonic()" name.

There is then a *different* use case, which is 3.3+ only code which
wants to fail noisily when there's no OS level monotonic support - the
application developer really does want to fail *immediately* if
there's no OS level monotonic clock available, instead of crossing
your fingers and hoping you don't hit a clock adjustment glitch
(crossing your fingers has, I'll point out, been the *only* option for
all previous versions of Python, so it clearly can't be *that* scary a
prospect).

So, rather than making time.monotonic() something that the *standard
library can't use*, I'd prefer to address that second use case by
exposing the OS level monotonic clock as time.os_monotonic() only when
it's available. That way, the natural transition for old time.time()
based code is to time.monotonic() (with no cross-platform support
implications), but time.os_monotonic() also becomes available for the
stricter use cases.

Regards,
Nick.

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


More information about the Python-Dev mailing list