-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
time: stop requiring Timer/Ticker.Stop for prompt GC #61542
Comments
Change https://go.dev/cl/512355 mentions this issue: |
This seems like it would require other Go implementations (such as gccgo and TinyGo) to implement those same special cases. Are we sure that's viable for them? |
That said, I think we basically have to do this to avoid the portability pitfall I mentioned in #8898 (comment). I don't want to be in a long-term state where it's ok to omit the |
I can't see why it wouldn't be a viable change for gccgo or TinyGo. The change is not terribly complex: it just requires recognizing timers supporting channels and turning them on/off around blocking operations on those channels. See https://go.dev/cl/512355. Also, we have never held Go back before for secondary implementations to catch up, and I am reluctant to start doing that now. In the second comment, I am not sure what "this" is in "basically have to do this". |
This proposal. That is: since the mainline implementation no longer requires a |
I see. I completely agree that if the CL is submitted then we have to accept the proposal. This proposal is really "should we submit the CL?" |
This proposal has been added to the active column of the proposals project |
@rsc If I understand the implementation correctly a tight for-select loop including a timer channel will cause frequent resorting of timer heaps. Is that a performance concern? Has it been measured? |
The timer heap manipulation only happens when the other channels are not ready. So how tight can the loop really be if it's constantly finding no channels ready and blocking on each iteration? I haven't figured out a good way to measure that. If you had a loop with a 1ns timer, that would get handled by a special polling check at the start of the channel operation and wouldn't involve the timer heap at all, so it should run faster than before. There may be a slower path here but I can't figure out how to provoke it if so. |
https://go.dev/cl/512355 is the code if anyone wants to try any benchmark attempts. |
That's a key piece of the implementation I hadn't realized. Thanks for the explanation. |
Does that optimization end up biasing |
It shouldn't bias it. If the timer channel is ready to send a value, then queues one up, and participates in the select statement as a ready channel. If the timer channel is not ready, then it doesn't. We only start worrying about the timer heap when no channels are ready. |
I spoke with the compiler/runtime team and nobody had objections to requiring the timer implementation to allow prompt GC. @aykevl and @deadprogram, I wanted to get your take on this proposal since TinyGo is the main other Go runtime and would have to implement this optimization. |
I downloaded the TinyGo distribution and looked to see how time.After was implemented. The answer appears to be that it is not implemented at all. It looks like if you use TinyGo you can have time.Sleep.
|
If I'm not mistaken, TinyGo just uses the time package from the main Go std. I believe this is their implementation of the runtime functions that underlie the time package: https://github.com/tinygo-org/tinygo/blob/v0.28.1/src/runtime/time.go and https://github.com/tinygo-org/tinygo/blob/v0.28.1/src/runtime/scheduler.go#L119 |
CC @dgryski (who has been doing some work on TinyGo) |
TinyGo does use the standard library (as much as we can), and we do support |
Based on the discussion above, this proposal seems like a likely accept. |
Would this also address #37196, or is that mostly orthogonal? |
I don't think it helps #37196 because in the worst case there is a long-running select already waiting on the channel, in which case the timer is in the heap and the behavior matches the current behavior. |
On the other hand the implementation changes for this issue definitely overlap with the already-accepted #37196, so I will take a look at whether I can do that while everything is paged in. |
No change in consensus, so accepted. 🎉 |
Finally got to this issue (holiday and all that). So right now we use the standard library time package and implement the runtime side of it in our custom runtime. That implementation isn't great: it basically calls the provided function from inside the scheduler so any blocking call is probably going to mess things up. Consider it a work in progress. Regarding the actual issue: it appears to require a bunch of special casing for timer channels. Maybe we'll implement that some day, but I can't promise that because it grows the runtime size even when timers aren't used and I very much would like to keep the runtime size as low as reasonably possible (while implementing the Go spec, of course). (At the same time, the current design of the TinyGo runtime should garbage collect deadlocked goroutines as a side effect of how the scheduler works. I didn't actually test this though. AFAIK the main Go runtime doesn't do this. Just to show a different design results in different things being trivial or difficult). |
After almost a decade, I have finally implemented #8898, special-casing the channels used for timers (or maybe the timers used for channels) so that the timers are not in the timer heap when there are no channel operations pending on them. This means that the channels and timers can be GC'ed once they are no longer referenced, without having to wait for a timer to expire or explicitly Stop the timer. (By timer here I mean the data structure used by time.After, time.NewTimer, and time.NewTicker.)
This raises a question: do we want to guarantee that all future versions of Go will provide this behavior, so that code can rely on not needing to call the Stop methods? I think we probably should make that guarantee.
I propose we land my CL and document that After can be used without concern for GC and that NewTimer and NewTicker can be used without concern for deferring Stop just for GC. At the moment the doc comment for After describes the problem and basically says "don't use this function a lot". If we accept this proposal, we can remove that text. NewTimer and NewTicker do not mention needing to call Stop, although it is implied by After's doc comment. If we accept this proposal, we can document that Stop is not necessary for GC, so that people can stop calling Stop.
The text was updated successfully, but these errors were encountered: