英文:
golang race with channels and return in a function
问题
我有以下3个文件:
go.mod
module example
go 1.19
main.go
package main
import "fmt"
func number(out chan int) bool {
defer close(out)
for i := 0; i < 5; i++ {
out <- i
}
return true
}
func main() {
in := make(chan int)
var ret bool
go func() {
ret = number(in)
}()
for i := range in {
fmt.Println(i)
}
if !ret {
fmt.Println(ret)
}
}
和 main_test.go
package main
import "testing"
func TestMain(t *testing.T) {
t.Run("test", func(t *testing.T) {
main()
})
}
我似乎遇到了ret
变量的竞态条件。为什么会出现这个问题?range in
不应该在number
函数中的通道关闭之前一直阻塞吗?因此,在读取ret
之前,它将具有返回的状态。此外,是否有一种方法可以解决这个问题,而不使用sync
包或另一个通道?
当我使用-race选项运行测试时,我得到以下错误$ go test -race
0
1
2
3
4
==================
WARNING: DATA RACE
Read at 0x00c00002023f by goroutine 8:
example.main()
/example/main.go:27 +0x174
example.TestMain.func1()
/example/main_test.go:13 +0x24
testing.tRunner()
/usr/local/go/src/testing/testing.go:1446 +0x216
testing.(*T).Run.func1()
/usr/local/go/src/testing/testing.go:1493 +0x47
Previous write at 0x00c00002023f by goroutine 9:
example.main.func1()
/example/main.go:20 +0x47
Goroutine 8 (running) created at:
testing.(*T).Run()
/usr/local/go/src/testing/testing.go:1493 +0x75d
example.TestMain()
/example/main_test.go:12 +0x64
testing.tRunner()
/usr/local/go/src/testing/testing.go:1446 +0x216
testing.(*T).Run.func1()
/usr/local/go/src/testing/testing.go:1493 +0x47
Goroutine 9 (finished) created at:
example.main()
/example/main.go:19 +0xfe
example.TestMain.func1()
/example/main_test.go:13 +0x24
testing.tRunner()
/usr/local/go/src/testing/testing.go:1446 +0x216
testing.(*T).Run.func1()
/usr/local/go/src/testing/testing.go:1493 +0x47
==================
--- FAIL: TestMain (0.00s)
--- FAIL: TestMain/test (0.00s)
testing.go:1319: race detected during execution of test
testing.go:1319: race detected during execution of test
FAIL
exit status 1
FAIL example 1.555s
英文:
I have the following 3 files:
go.mod
module example
go 1.19
main.go
package main
import "fmt"
func number(out chan int) bool {
defer close(out)
for i := 0; i < 5; i++ {
out <- i
}
return true
}
func main() {
in := make(chan int)
var ret bool
go func() {
ret = number(in)
}()
for i := range in {
fmt.Println(i)
}
if !ret {
fmt.Println(ret)
}
}
and main_test.go
package main
import "testing"
func TestMain(t *testing.T) {
t.Run("test", func(t *testing.T) {
main()
})
}
I seem to hit a race condition with the ret
variable. Why is this an issue, shouldn't range in
be blocking till the channel is closed in the number
function. And hence ret
will have the returned status, before it is read? Also, is there a way to resolve this without using the sync package or another channel?
When I run the test with -race option, I get the following error $ go test -race
0
1
2
3
4
==================
WARNING: DATA RACE
Read at 0x00c00002023f by goroutine 8:
example.main()
/example/main.go:27 +0x174
example.TestMain.func1()
/example/main_test.go:13 +0x24
testing.tRunner()
/usr/local/go/src/testing/testing.go:1446 +0x216
testing.(*T).Run.func1()
/usr/local/go/src/testing/testing.go:1493 +0x47
Previous write at 0x00c00002023f by goroutine 9:
example.main.func1()
/example/main.go:20 +0x47
Goroutine 8 (running) created at:
testing.(*T).Run()
/usr/local/go/src/testing/testing.go:1493 +0x75d
example.TestMain()
/example/main_test.go:12 +0x64
testing.tRunner()
/usr/local/go/src/testing/testing.go:1446 +0x216
testing.(*T).Run.func1()
/usr/local/go/src/testing/testing.go:1493 +0x47
Goroutine 9 (finished) created at:
example.main()
/example/main.go:19 +0xfe
example.TestMain.func1()
/example/main_test.go:13 +0x24
testing.tRunner()
/usr/local/go/src/testing/testing.go:1446 +0x216
testing.(*T).Run.func1()
/usr/local/go/src/testing/testing.go:1493 +0x47
==================
--- FAIL: TestMain (0.00s)
--- FAIL: TestMain/test (0.00s)
testing.go:1319: race detected during execution of test
testing.go:1319: race detected during execution of test
FAIL
exit status 1
FAIL example 1.555s
答案1
得分: 2
当在main
函数中读取ret
时,可以确保通道已关闭,但不能确保对ret
的赋值已完成。因此,这是一个竞争条件。
英文:
When ret
is read in main
, it is guaranteed that the channel is closed, but it is not guaranteed that the assignment to ret
is completed. Thus, it is a race.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论