-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Undeprecate thread::sleep_ms
#51610
Undeprecate thread::sleep_ms
#51610
Conversation
Sleeping is very useful for `printf`-debugging of concurrent code, and `::std::thread::sleep_ms(300)` is much more convenient that `::std::thread::sleep(::std::time::Duration::from_millis(300))`.
r? @cramertj (rust_highfive has picked a reviewer for you, use r? to override) |
r? @rust-lang/libs |
Note that #51418 proposes to add |
I agree with the motivation, I would rather not write the whole sleep(92*MILLIS)
sleep(92*MINUTES)
sleep(92*HOURS) where |
For reference, this is the deprecation pr: #29604 |
Team member @withoutboats has proposed to merge this. The next step is review by the rest of the tagged teams: Concerns:
Once a majority of reviewers approve (and none object), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
I don’t mind un-deprecating, but historically we’ve put the bar much higher than this for inclusion in the prelude. I don’t know if they’re formally written down anywhere, but if we want to revisit those inclusion criteria that’s a larger discussion. |
Is this proposed as a one-off special case or should we have a _ms equivalent of every duration-consuming method? |
Sorry, I've expressed my thought in a very confusing way. I do not want to add
As a special case: |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
I've found In the tests for If we undeprecate select! {
recv(r2, v) => assert!(v.is_none()),
recv(channel::after(ms(1000))) => panic!(),
} Therefore,
I find the suggestion by @mark-i-m the most appealing: introducing constants of type thread::sleep(100 * MILLIS);
select! {
recv(r2, v) => assert!(v.is_none()),
recv(channel::after(1 * SECONDS)) => panic!(),
} It's worth noting that Go similarly defines a list of constants in the const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
) |
@stjepang Adding some constants to use std::time::MILLISECOND;
use std::thread::sleep;
sleep(92 * MILLISECOND); (I see that we have |
@rfcbot concern duration-constants-instead |
@SimonSapin Having such constants in the prelude would be nice, but I'd be fine with manual imports, too. |
For my use-case of quickly adding a call to sleep specifically, I would say that I also would like to note that @stjepang 's use-case is exactly the opposite of what I am describing in the issue: in crossbeam channel, timeouts are exactly the thing which is being tested, it is absolutely not a quick & dirty kind of code I have in mind. That said, I agree that that we also have a problem of "Duration is unergonomic to create", and that constants look like a good solution to it (though they'll be more shouty than Go's ones... EDIT: well, |
@rfcbot concern dissensus I wasnt in the libs team meeting but I'm pretty strongly in favor of merging this undeprecation. I think APIs should only be deprecated because they are strictly inferior to other APIs; I don't understand why we would tell people with certain use cases that they should just ignore the deprecation warnings telling them not to use an API? |
This API was stabilized at 1.0 with the explicit intention of being deprecated as soon as we figured out The addition of
All of these were existing problems with That's all to say that Now the argument here is crucially hinged on convenience. This was not a motivational factor in the design for either iteration. The original I personally feel that this is not worth it. This is setting a clear precedent for the ecosystem of "hey Duration isn't ergonomic, you probably want to use it but also have methods that don't use it". That's not the precedent the standard library wants to set. Instead I think we should invest in an alternate route of making the current iteration more ergonomic, benefitting everyone using Calling |
Frameworks like Ruby on Rails add methods to integers for the same purpose. Both routes are possible in Rust: trait DurationExt {
fn millis(self) -> std::time::Duration;
}
impl DurationExt for u64 {
fn millis(self) -> std::time::Duration {
std::time::Duration::from_millis(self)
}
} #[derive(Debug, Copy, Clone)]
struct Millis;
impl std::ops::Mul<Millis> for u64 {
type Output = std::time::Duration;
fn mul(self, _other: Millis) -> Self::Output {
std::time::Duration::from_millis(self)
}
} use std::thread::sleep;
fn main() {
sleep(32.millis());
sleep(32 * Millis);
} I'm in favor of something like this to extend the ergonomics to every Duration-taking function, such as those found in networking code. |
Both |
Oh, I wasn't even proposing such, just dumping implementations in case someone wants them. |
Sure, I’m just saying the import should be kept in mind when evaluating how ergonomic such a solution would be. |
In my experience, when I need sleep, it isn't just once but multiple times, so the import is amortized over multiple usages. |
@withoutboats do you have thoughts on what's mentioned above? Does it resolve your concern? |
ping @withoutboats, this FCP is currently blocked on your concern |
@rfcbot resolve dissensus I still think we should accept this PR but don't have the time to hash this out now. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
Another potential way to make something like
Alternatively it can be argued that perhaps AsRef is more appropriate than Into, but that's a relatively minor nitpick. But technically it would be a breaking change. |
The final comment period, with a disposition to close, as per the review above, is now complete. |
Ping from triage! Since the FCP to close is over, without any additional discussion, I'll assume that the original decision stands and close the PR. |
I've opened a PR to add duration constants: #57375 |
Hi! Currently,
thread::sleep_ms
is deprecated in favor ofthread::sleep
, but I want to argue that_ms
variant is really useful and we should un-deprecate it :)sleep
is an odd function, in that it is rarely useful in "real code"; you almost always want to wait for some condition to happen rather than just sleep for some wall-clock time.However, there are two "not real code" cases where sleep is used a lot:
Debugging: it might be useful to insert
sleep(a little)
to freeze the system in some particular state. For example, it could be useful to wait to be able to attach debugger to some process, or to expose some race condition.Tests: although sleep in tests is in general an awful idea, sometimes there's just no way around it, and in test code such "correct with some luck" code might actually be acceptable. As an example, in Cargo tests we sleep for a second sometimes because mtimes on MacOS have resolution of one second.
Both of this use-cases are write once/read never, and you have the time to sleep as an integer constant. For such use-cases
sleep_ms(92)
is so much shorter and clearer thansleep(Duration::from_millis(92))
.Moreover, for debugging case you'd really want to avoid adding imports (luckily, we live in a glorious age when IDEs can insert imports for you automatically, but you will forget to remove the import once sleep is deleted), and the difference between
::std::thread::sleep_ms(92)
and::std::thread::sleep(::std::time::Duration::from_millis(92))
is even more pronounced!I think there are no problems with
sleep_ms
per se, besides it being non-orthogonal withsleep
? It should be fine to add common-case utility functions which are expressed in terms of underling low-level API (case study:println
andeprintln
). <sarcasm>One potential problem is that someone could try to usesleep_ms
to sleep for a givenDuration
. Luckily, it is excruciatingly non-trivial to extract milliseconds from aDuration
, and this should help the user to discoverthread::sleep
</sarcasm>.Note: we actually have
sleep_ms
function in Cargo for tests specifically.