Like John said, this seems like a straightforward bug, rather than something that has to be legislated on evolution. nil should be a sensible default value for the platform.
Like John said, this seems like a straightforward bug, rather than something that has to be legislated on evolution. nil should be a sensible default value for the platform.
I respectfully disagree. The default implementation is a matter for Swift Evolution because it really affects how the code behaves and how programmers need to write the code. If we keep them as is, then it's either tolerance: .zero/.milliseconds(very small number) or a footgun.
All I'm asking is that we add to this proposal that the default clocks will cap the timer coalescing window to the smallest amount that can be cheaply achieved (e.g. 15.6ms for Windows, 0 for Linux, 0 for macOS and some other small-ish number for iOS/watchOS/...). Even better would be to make it an application-defined setting (with reasonable platform defaults) as @ksluder suggested.
And I think it's especially important to do this now and with this proposal because deadlines are often long (in the minutes). So the current coalescing behaviour is really harmful and yet not in contradiction of the specification.
Given the competing interests here, I don’t think the stdlib can promise any maximum coalescing quantum. Consumer Darwin platforms will coalesce timers across very long intervals.
To get more specific, I was thinking an environment variable like SWIFT_DEFAULT_TIMER_TOLERANCE would be a good way to override the platform-default tolerance. For Windows services, this would require modifying the service’s registry entry.
Well, we can't promise anything specific with timers at all; we're not casually making real-time guarantees here. But we should definitely be capping the default tolerance instead of just using a raw percentage, and that cap should probably default to something on the order of 10–20ms. And having it be configurable at runtime by an environment variable makes a lot of sense on top of that.
Are we talking about non-Apple platforms here? Because our OSes already have default timer coalescing semantics which are dynamic based on application usage. I assumed nil would map to those existing behaviors.
I think this proposal should match the behavior of existing tolerance: parameters in other concurrency APIs and then we should consider whether to change the behavior of all tolerance: parameters in a separate proposal. If there's one thing we can conclude from the review threads so far, it's that this is a pretty nuanced question; it might even need to be configurable on a per-application basis. That sounds like a complicated enough design to deserve its own proposal.
I wasn't aware of the details of this; thank you for the link, it was useful for looking up other documentation.
The Swift runtime does just call down to dispatch_after. The open-source libdispatch uses a default tolerance of 10% of the duration, capped to 60s. That cap does seem quite high for a default, and I would say it's a reasonable feature request for Dispatch to allow it to be globally configured.
Well, we can't promise anything specific with timers at all; we're not casually making real-time guarantees here. But we should definitely be capping the default tolerance instead of just using a raw percentage, and that cap should probably default to something on the order of 10–20ms. And having it be configurable at runtime by an environment variable makes a lot of sense on top of that.
Sounds good. Can we include this in the proposal then?
Apart from an env var, we will also need an in-program/build time config for this, kinda odd if you need to set an env var for your server application to work correctly.
No, I think that belongs as a separate proposal that applies across timer-related APIs. Not sure whether it really needs evolution discussion vs. just being a Dispatch implementation question.
My gut feeling is that it’s basically “just” a bug that we can fix, but we might want to have an evolution discussion to formalize the policy.
To clarify, is the “bug” that Swift defaults to a non-zero tolerance, or that there’s currently no way to override the default on a per-process or per-host basis?
The "bug" in my mind is that:
- the runtime defaults to tolerance that's much too lax for some uses even on client
- no one seems to have considered changing the default for server
- there's no clear hook for platforms/applications to override the default if needed
No, I think that belongs as a separate proposal that applies across timer-related APIs. Not sure whether it really needs evolution discussion vs. just being a Dispatch implementation question.
I agree that we should fix it everywhere but I think specifically for deadlines it is required because they are frequently long so we're guaranteed to see the negative effects. I worry that if we don't require it, we'll just file it as a bug and then release the next version with the bug in there. This would require lots of Swift programmers to work around this for a protracted amount of time -- especially because on Darwin-based systems this ships with the operating system. So to be safe you'd need to either just pass .zero (or similarly) everywhere or do a runtime OS check which isn't great.
I want to second this, even if I don't have a strong opinion on what the behavior should be. I've dealt with supporting different behaviors on old OS versions enough to want to prevent that wherever possible.