执行测试并执行以下通道代码,但结果不同。为什么?

时间:2020-02-28 09:31:00

标签: go

main.go

func main() {
    fmt.Println("hello")
    ch := make(chan struct{}, 1)
    <-ch
}
main_test.go

func Test_Main(t *testing.T) {
    main()
}

运行main.go

  hello
  fatal error: all goroutines are asleep - deadlock!
  goroutine 1 [chan receive]:
  main.main()

但是 去测试-v main_test.go -run = Test_Main

=== RUN   Test_Main
hello

go测试不会报告错误,并且将始终运行。 在咨询了很多信息之后,我没有找到解释这种现象的答案。也许我的方法是错误的?此通道方法用于项目中。 谢谢。

1 个答案:

答案 0 :(得分:1)

运行常规程序时,它将等待通道的输入。而且,由于只有一个goroutine,因此无法从通道接收输入(没有其他线程可以发送给它)。因此报告了死锁。

另一方面,测试运行程序使用goroutines执行测试。因此,产生了一个以上的goroutine,并且没有检测到死锁(运行时假定其他goroutine可以发送到通道)。

从评论中回答您的问题:运行和测试不应达到相同的效果。 go run执行您的程序,go test执行测试您的代码的过程。这些命令执行两个不同的程序。

我不确定是否可以通过测试检测到此类错误(死锁)。

编辑: go test等待测试完成(您可以使用-timeout d选项配置多长时间)。因此,我假设它会生成等待timer.Timer过期的goroutine,因此不会出现死锁(总是有一个goroutine可以执行)。

Edit2: 试试这个程序:

package main

import (
    "fmt"
    "time"
)

func main() {
    go func() {
        t := time.NewTimer(10 * time.Second)
        <-t.C
    }()
    fmt.Println("hello")
    ch := make(chan struct{}, 1)
    <-ch
}

它会等待10秒钟,然后报告死锁。

Edit3: 或看看说明测试运行器如何工作的流畅代码:

package main

import (
    "fmt"
    "time"
)

func original_main_func() {
    fmt.Println("hello")
    ch := make(chan struct{}, 1)
    <-ch
}

func test() {
    original_main_func()
}

func test_runner() {
    ch := make(chan struct{}, 1)
    go func() {
        test()
        close(ch)
    }()
    t := time.NewTimer(10 * time.Second)
    select {
    case <-t.C:
        panic("timeout")
    case <-ch:
        fmt.Println("test executed")
    }
}

func main() {
    test_runner()
}