-
Notifications
You must be signed in to change notification settings - Fork 17.5k
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
runtime: confusing panic on parallel calls to yield function #68897
Comments
found a weired gowrap1 if run with race detector go run -race ./play/WARNING: DATA RACE Previous write at 0x00c00000a198 by goroutine 7: Goroutine 8 (running) created at: Goroutine 7 (running) created at: |
I can recreate this on my laptop, but only if I use It's hard to see how parallel calls to a yield function could work, but we should see if we can produce a better error message for this case. |
you are calling |
CC @dr2chase |
But there is a (*sync.WaitGroup).Wait(), why would the main goroutine be finished without respecting the waitgroup? func main() {
WaitAll(10)(func(i int) bool {
fmt.Println(i)
return true
})
} |
remove everything related to the |
I want to simplify the WaitGroup boilerplate. I think the wait group does matter, because I want it to wait all of the yield call. |
@thediveo I agree that some panic would be acceptable for this program, but "range function continued iteration after loop body panic" is just inaccurate. The loop body did not panic. |
@hauntedness Why do you want to call the yield function in parallel in different goroutines? |
The requirement is that a yield function may be called if all calls to the yield have returns true and f has not terminated. This bans parallel calls. (Not calls from multiple Go routines.)
A panic happening here is WAI.
I am about 90% sure this is the state variable for the loop being being set to the state that detects early exits (panics) still being set when a parallel call happens and it is read. A different wording seems appropriate. |
I want less boilerplate... |
Thanks for those information but it will not always panic. eg. Below doesn't panic func main() {
sum := 0
for i := range WaitAll(10) {
sum += i
}
fmt.Println(sum)
} |
@timothy-king |
There is to the best of my knowledge no specification given as to the temporal behavior of overlapping If I understand this correctly then your code happens to work on some systems some times, but might have never been guaranteed by the spec to be supported. |
@hauntedness The rule that @timothy-king stated is "a yield function may be called if all calls to the yield have returns true and f has not terminated." Your program does not obey that rule. It calls the yield function even though a previous call to the yield function has not yet returned. That is, it makes multiple calls to the yield function in parallel. The fact that in some cases your program does not panic does not mean that your program is following the rules. |
@ianlancetaylor |
Yes: you can't call yield until the previous call to yield has returned. In the language spec this is written as (https://go.dev/ref/spec#For_statements):
I think it's too early to say whether we need a vet check for this. We only want vet checks for errors that are frequently made. This strikes me as unlikely to be frequent. I also don't know how we could write an accurate vet check here. |
It should be able to. You probably are just not getting unlucky. Try increasing the constant to a few hundred thousand and turning on -race.
For WaitAll(10), after the second iteration there will be two newly go routines. So 3 goroutines: the original, the goroutine created for j==0, and the goroutine created for j==1. Now suspend the original go routine, schedule the j==1 goroutine and execute to the body of the yield (right before fmt.Println), and now schedule j==1 goroutine, and execute until it calls yield. The call the yield from j==0 has not returned true yet. This is a violation.
The implementations definitely believe this is the requirement. The spec hints at this (everything after "If yield is called before f returns," is calling out specific conditions). IMO could/should spell this out more. (IMO the even bigger hole in the spec is that
Correct. The code below sequences yield calls correctly (even if it 'misses the point'):
Maybe. We discussed this before the release. The discussion concluded that we need more evidence of what to check for before creating a proposal/checker. As for "super hidden", we can advertise this better in the spec or a future blog post. |
I actually meant what you so succinctly put into words, where I utterly failed with mine. |
CC @golang/compiler |
Go version
go1.23.0-windows-amd64
Output of
go env
in your module/workspace:What did you do?
See https://go.dev/play/p/_X0iHMy6lH1
What did you see happen?
==================
panic: runtime error: range function continued iteration after loop body panic
goroutine 21 [running]:
main.main-range1(0x2)
D:/temp/dot/play/iter.go:9 +0xf3
main.main.WaitAll.func1.1(0x2)
D:/temp/dot/play/iter.go:21 +0x8c
created by main.main.WaitAll.func1 in goroutine 1
D:/temp/dot/play/iter.go:19 +0x8c
exit status 2
What did you expect to see?
No panic
The text was updated successfully, but these errors were encountered: