-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
proposal: runtime: add WaitIdle function #65336
Comments
For reference, there is currently a similar function (but with a narrower scope) in the main repo: This also demonstrates that it is currently possible to implement this function as a third-party library, albeit a somewhat fragile one — it depends on the exact format of |
would this be the same as #44026 ? |
@bcmills I'm currently using a similar implementation, but created this proposal to see if there is interest in adding first-class support for it to the runtime, seeing that it could be a common use case. @seankhliao This is different from a deadlock detector, which detects the case where all goroutines are in the waiting state, there are no active timers or netpoll sockets, and really only works when cgo is disabled. This only considers the case where all goroutines are in the waiting state, which can be useful for multiple real-world uses:
|
This proposal was mostly inspired by the this function in the Rust Tokio library, which implements a feature that I found immensely helpful for writing deterministic unit tests: it waits until the runtime has no work to do, then auto-advances the simulated runtime timer to the the next wakeup time. Adding |
Hi all, just wanted to bump this proposal, and please let me know if there's anything that needs to be done on my end :) |
@neild has been investigating similar issues. There's something useful to do here, but I'm not sure this exact API is it. |
You can implement something like this today using Based on my experience with that approach, I think my ideal API might be something like:
I don't really like the "Group" name, but I don't have a better one. Idle-wait operates on a tree of goroutines (a goroutine, and all goroutines transitively created by it). This seems like the right approach for testing concurrent functions. Perhaps more controversially, Wait does not consider a goroutine which is sleeping or blocked on IO to be idle. A goroutine which is sleeping will eventually wake: It is not idle. A goroutine reading from a network connection may or may not wake in the future, but the runtime cannot say that it will not. In particular, if we write to a local network socket and then immediately wait, a goroutine reading from the other end of the socket might appear to be briefly idle until the data traverses the kernel. Limiting Wait to cases when a goroutine is deterministically and permanently blocked should make it a bit harder to produce flaky tests with it, and could allow for telling the race detector that it creates a happens-before relationship. |
This proposal has been added to the active column of the proposals project |
These two seem to be in conflict for a goroutine that does |
In my ideal world, we'd treat timer channels differently. Whether that's practically possible, I don't know. |
Filed #67434 with an alternate idea, covering both idle detection and fake timers. |
For the uses cases defined here, I do think it's acceptable for this to be a global construct because restricting the behavior over a set of goroutines effectively gives each goroutine an "identity", which the Go runtime ideologically tries really hard to avoid, e.g. the library intentionally avoids exposing a goroutine ID for this reason. In the case where
I am currently using this approach with my mock timer implementation, but |
It seems like closing this as a duplicate of #67434 is reasonable. |
Though the general idea of this proposal and #67434 are similar, I believe it is worth keeping this proposal open and discussing both options in parallel due to some major differences:
|
Those are differences, but are they advantages? What kind of tests would be easier to write with this proposal than with #67434? |
I agree that the two proposals have differences, but it seems clear we are only going to do one. The issues you list seem like downsides of this proposal to me:
If you feel strongly that one of these details is wrong in #67434, please comment there. |
Based on the discussion above, this proposal seems like a likely decline. |
No change in consensus, so declined. |
Proposal Details
I propose adding a new function
WaitIdle
toruntime
.The function will have the following function signature:
WaitIdle will return a channel that will be closed at the next moment that no goroutines are runnable, i.e. all P's are idle. This channel would be woken up when
pidleput()
is called for the last active P.The main use case of the WaitIdle function is for tests, where a user or library may need to wait for all downstream effects of a given wakeup to complete before proceeding with the test case.
For example, a hypothetical mock time implementation may be used by hypothetical user code in a test harness as follows:
In order for the call to
mocktime.Now()
to be deterministic, the implementation must wait until the effects of waking up theticker
channel have completed, e.g. waiting until the goroutine with the user code is once again waiting onticker
or some other channel. Some mock time implementations use a stand-in method such astime.Sleep(1 * time.Millisecond)
to wait for user goroutines to settle; however, this is unreliable for CPU-heavy goroutines, and slow for goroutines that execute minimal code upon wakeup. As long as the user code does not call the realtime.*
functions or other I/O functions, usingWaitIdle()
here would provide both determinism and a performance benefit.Implementation of proposal here.
The text was updated successfully, but these errors were encountered: