golang与函数中的通道和返回进行竞赛

k7fdbhmy  于 2023-01-10  发布在  Go
关注(0)|答案(1)|浏览(127)

我有以下3个文件:第一个月

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将在读取之前返回状态?还有,是否有一种方法可以在不使用同步包或另一个通道的情况下解决这个问题?
当我使用-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
ztmd8pv5

ztmd8pv51#

ret被读入main时,可以保证通道被关闭,但不能保证对ret的分配完成,因此,这是一个竞争。

相关问题