-
-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
Feature request: Finer-grained sleep function #54971
Comments
Looks similar to #12770 |
Wow, 2015! Okay maybe this just needs a PR at this point rather than an issue.. |
This is not the API of |
You are fast! I realised my mistake and deleted the comment about 30 seconds after posting 😅 Cunningham's law shows no mercy |
@MilesCranmer Feel free to create a pull request for https://github.com/ufechner7/Timers.jl if you have a good idea for a new sleep function and what to test it out before creating a pull request to Julia directly. |
Thanks, I will probably just go with this code for now: function systemsleep(seconds::Real)
microseconds = round(Int, 1e6 * seconds)
@threadcall(:usleep, Int, (Int,), microseconds)
return nothing
end It's small enough that I will just stick it directly in my library, but thanks for the offer.
I think a "proper" solution to all of this should handle it directly in C with |
It's not particularly difficult for us to add a new |
I think for Windows it could just fall back to regular |
How do these short system sleeps compare to
It looks like it works pretty well down to ~10 microsecond (and below that, you probably should just busy-wait).
|
I guess the downside of this |
That's fair, the better version of this function probably includes a check for whether |
But this would really depend on the context as usually you wouldn't have a one-off |
I don't think you can get accurate times and low CPU usage with a loop of short sleeps. (since if you yield back to the OS, you can't know that you will be scheduled in time). If you are using this to try to respond to incoming events, you really want a push based system (or something like |
Just to be clear I didn't mean using a loop of short sleeps to emulate a single long sleep... I meant doing small tasks with short sleeps between them. |
Another example: I want to check if a file exists, and check regularly (<1ms) so I can react to updates. This is where a short |
For the file existence example, there are OS APIs to receive notifications that a file has been created/destroyed etc and C# for example, has a platform independent API that wraps them https://learn.microsoft.com/en-us/dotnet/api/system.io.filesystemwatcher?view=net-8.0 OnCreated(FileSystemEventArgs). Specifically, for this use-case, you would call I agree with your general point that we should make |
I have looked into adding a higher precision mode to libuv, but on Windows (contrary to the python documentation, but per the kernel documentation linked to by the python documentation as its citation), the minimum possible sleep request is 1ms, and often it will round-up significantly more (usually up to the nearest 15ms interval). As Oscar mentioned, there are usually better ways to deal with short sleeps. For example, polling a file at 1ms will still often miss most updates to the file (as most updates to it won't change the metadata of the file), in addition to wasting a lot of computer time, that a call to the kernel filewatching stdlib would have gotten correct more often. |
Do we need/want libuv support for short sleeps? I think it would be reasonable to make sleeps less than 1ms be a yield loop even if libuv supported short sleeps. |
I think if the operating system makes it possible to sleep for a certain interval under a millisecond, Julia should make that function available to the user without added overhead, blocking, or CPU usage. |
The question with the python implementation is what happens if you request a sleep for (say) |
I'm not sure Anyways, in Python, [nav] In [2]: import time
[ins] In [3]: %%timeit
...: time.sleep(5e-7)
...:
...:
1.91 µs ± 18.5 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each) I think even julia> @btime sleep(5e-7)
1.145 ms (4 allocations: 112 bytes) |
For reference, these are the main functions used by the python sleep code on Windows:
The docs for the second function mention:
So it sounds like you can "request" sleep times in 100 ns intervals, but the actual accuracy is hardware-dependent. The code shows that there's also an early-quit branch if sleep of 0 is passed – which calls In any case it would be nice to have access to this :) |
Interesting. It seems that as of 2022, Python developers could prove in testing that the code didn't work (instead giving 16ms resolution) per https://bugs.python.org/issue45429 |
Also, just to point out the obvious: 1ms is already 1000 frames per second and therefore already significantly more than the OS checks for new keystrokes |
I'm reading that thread now and they say |
Ah, I see now where in the thread they mention this was implemented in the NT kernel in late 2021. I had not know that, as the documentation seems to not be fully updated for it |
I don't think this is quite right. As I understand it, 1000hz polling rates were fairly common for gaming mice/keyboards. |
Not with a stock kernel, though you can compile your own to increase it up to 1khz eg https://superuser.com/questions/369826/increase-usb-polling-rate-across-all-devices-in-linux |
Base.sleep
has a minimum time of 1 millisecond. This is very coarse compared to other high-performance languages like C and Rust and can cause some issues for some applications (see thread) such as periodically polling workers without blocking the main thread.In other languages, for example, Python can actually get fairly high resolution with the default
time.sleep
(although its blocking):which calls the corresponding system sleep.
Rust has:
which calls the system sleep in a thread.
One workaround is to use
Libc.systemsleep
. However, this blocks the calling thread. Similarly, one can usetime()
in a while-loop, but this also blocks.One option which I would like comments on is the following function which is basically a non-blocking call of
usleep
by the use of@threadcall
:This is OS-dependent and on some systems will not be better than
sleep
. But it's at least better for unix systems. With this function, one can get a higher resolution thanBase.sleep
:with the smallest time being about 20us (presumably due to overhead of
threadcall
)There is also
nanosleep
which is another option to consider for this task: https://linux.die.net/man/2/nanosleep.The text was updated successfully, but these errors were encountered: