Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow sleeping until an absolute time #101558

Open
haukex opened this issue Feb 4, 2023 · 7 comments
Open

Allow sleeping until an absolute time #101558

haukex opened this issue Feb 4, 2023 · 7 comments
Assignees
Labels
stdlib Python modules in the Lib dir type-feature A feature request or enhancement

Comments

@haukex
Copy link

haukex commented Feb 4, 2023

I propose a version of time.sleep() that allows for the specification of absolute times.

Python 3.11 added the use of clock_nanosleep in time.sleep() (#28111), and both it and Windows' SetWaitableTimerEx allow for the specification of absolute times. This can be useful for writing simple loops that trigger at an interval that is tied to wall-clock time, which has many applications: triggering taking of measurements, pictures, checking status, sending messages, ...

With time.sleep(), one has to emulate this by saying time.sleep(deadline - time.time()), which pysleep then calculates back into an absolute time internally, which adds inaccuracy.

I will be submitting a pull request shortly that modifies pysleep to give it an "absolute" argument and adds a time.sleep_until() function.

Linked PRs

@haukex haukex added the type-feature A feature request or enhancement label Feb 4, 2023
haukex added a commit to haukex/cpython that referenced this issue Feb 4, 2023
Adds the `time.sleep_until` function, which allows sleeping until the
specified absolute time.
@arhadthedev arhadthedev added the stdlib Python modules in the Lib dir label Feb 4, 2023
@SimpleArt
Copy link

Worth pointing out that I would love to have the equivalent functions like asyncio.sleep_until. Not sure if there's any other sleepers to look for.

@haukex
Copy link
Author

haukex commented Feb 6, 2023

I checked the implementation, and loop.time() is just time.monotonic(), and the loop is apparently implemented with select() (from selectors or IocpProactor on Windows). I'm not an expert on this but it seems like it might be fairly complicated to implement on a low level, so perhaps in that case it would need to be implemented at a higher level.

@abalkin abalkin self-assigned this Feb 6, 2023
haukex added a commit to haukex/cpython that referenced this issue Feb 11, 2023
Adds the `time.sleep_until` function, which allows sleeping until the
specified absolute time.
@haukex
Copy link
Author

haukex commented Feb 12, 2023

Additional arguments for this feature suggestion provided here: #101559 (comment)

haukex added a commit to haukex/cpython that referenced this issue Feb 12, 2023
Adds the `time.sleep_until` function, which allows sleeping until the
specified absolute time.
@SimpleArt
Copy link

I think that for asyncio it's possible to use what asyncio.sleep already uses underneath. On the first call, an estimate of loop.time() could be made in absolute time, and every subsequent call is relative to that time by sleeping until loop.time() + (timestamp - abs_loop_time), calling what asyncio.sleep uses. This prevents accumulated inaccuracies if multiple asyncio.sleep(seconds) calls are made instead of using multiple asyncio.sleep_until(timestamp).

@haukex
Copy link
Author

haukex commented Mar 18, 2023

I still don't know of an async equivalent of the system call clock_nanosleep - and this system function is the main reason I raised this issue. But perhaps loop.call_at can be used in the emulation for asyncio.

haukex added a commit to haukex/cpython that referenced this issue Apr 10, 2023
Adds the `time.sleep_until` function, which allows sleeping until the
specified absolute time.
haukex added a commit to haukex/cpython that referenced this issue Apr 11, 2023
Adds the `time.sleep_until` function, which allows sleeping until the
specified absolute time.
@jcalvinowens
Copy link

I'd love to see the PR attached here merged. To implement a periodic task in a Python loop, one is currently forced to do a racy subtraction with the current time. The pull request attached to this proposal fixes that.

To print 'A' at 100hz, one might naively write:

    while True:
            print('A')
            time.sleep(0.01)

...but of course, that's not really going to yield a coherent 100hz. There are many applications where that matters, such as sampling a sensor to produce timeseries data.

If you actually care, you're forced to do something like this:

    p = time.time()
    while True:
            print('A')
            time.sleep(time.time() - p + 0.01)
            p = time.time()

...but that's inherently racy. If this proposal is implemented, that loop could become:

    p = time.time()
    while True:
            print('A')
            time.sleep_until(p + 0.01)
            p += 0.01

...which both simplifies the code, and eliminates the race condition. On platforms where there isn't support for TIMER_ABSTIME, it could fall back to the racy subtraction (which is what the user would've done anyway).

@hauntsaninja
Copy link
Contributor

pganssle's comment sums up the current state here: #101559 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stdlib Python modules in the Lib dir type-feature A feature request or enhancement
Projects
Development

No branches or pull requests

6 participants