Go 中如何调用测试函数?

问题描述 投票:0回答:2

我正在学习Go语言,现在有一个问题

我只是在测试缓冲和非缓冲通道。

在为它写测试代码的时候,出现了一个看不懂结果的情况

func BenchmarkUnbufferedChannelInt(b *testing.B) {
    ch := make(chan int)
    go func() {
        for i := 0; i < b.N; i++ {
            ch <- i
        }
    }()

    for {
        <-ch
    }
}

上面的代码没有停止,因为

<-ch
让goroutine永远阻塞。但是,下面的代码不会创建阻止状态并且测试成功。

func BenchmarkUnbufferedChannelInt(b *testing.B) {
    ch := make(chan int)
    go func() {
        for {
            <-ch
        }
    }()

    for i := 0; i < b.N; i++ {
        ch <- i
    }
}
BenchmarkUnbufferedChannelInt
BenchmarkUnbufferedChannelInt-12         8158381               142.1 ns/op
PASS

据我所知,goroutine之间没有父子关系,所以一个goroutine的终止不会影响除main goroutine之外的其他goroutine的终止。

理论上,以上两种代码最终都应该永远被阻止。

但是不知道为什么只有第二个代码成功了

我想知道 Go 是如何调用测试函数的。假设测试函数运行的 goroutine 与 main goroutine 具有相同的特征,我可以理解上面代码的结果。

但如果不是,我不明白。在这两个测试中,goroutine 最终应该永远被阻塞。

你能解释一下上面的结果吗?请!

go goroutine go-testing
2个回答
1
投票

上面的代码没有停止,因为

<-ch
让goroutine永远阻塞。

不,因为无限

for
循环被阻止了

然而,下面的代码并没有创建阻塞状态,测试成功。

正确,因为

for
循环运行的次数与您希望基准测试运行的次数一样多。一旦这个循环结束,你启动的 goroutine 就会被遗忘,你就有了泄漏。请参阅https://www.ardanlabs.com/blog/2018/11/goroutine-leaks-the-forgotten-sender.html如果您启动一个 Goroutine,您希望最终终止但它永远不会终止,那么它有泄露了


0
投票

在你的第二个例子中,goroutine 无限期地阻塞,这在技术上是一个泄漏但不会阻塞程序本身。

在您的第一个示例中,您无限期地循环在goroutine之外,因此程序将阻塞。这不是 Go 特有的,也与从频道接收没有真正的关系。你只是在没有退出条件的情况下循环,例如

while (true) {}
任何其他语言。

确保你没有在 goroutine 中无限循环以防止它泄漏。此外,一旦通道被清空并关闭,通道上的范围就会停止,因此您可以在完成填充后在 goroutine 中关闭它并改为范围:

func BenchmarkUnbufferedChannelInt(b *testing.B) {
    ch := make(chan int)
    go func() {
        for i := 0; i < b.N; i++ {
            ch <- i
        }
        close(ch)
    }()

    for _ := range ch {

    }
}
© www.soinside.com 2019 - 2024. All rights reserved.