go test и go run выполняют следующий код канала, но результаты отличаются. Почему? - PullRequest
0 голосов
/ 28 февраля 2020
main.go

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

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

go run main. go

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

но go test -v main_test. go -run = Test_Main

=== RUN   Test_Main
hello

go test не выдаст сообщение об ошибке и всегда будет выполняться. Изучив много информации, я не нашел ответа, чтобы объяснить это явление. Может быть, мой путь неправильный? Этот метод канала используется в проектах. Спасибо.

1 Ответ

1 голос
/ 28 февраля 2020

Когда вы запускаете обычную программу, она ожидает ввода от канала. И поскольку существует только одна процедура, нет способа получить входные данные из канала (нет другого потока для отправки на него). Таким образом, тупик сообщается.

С другой стороны, для выполнения тестов для выполнения тестов используются программы. Таким образом, появляется более одной программы, и тупик не обнаружен (среда выполнения предполагает, что другая программа может отправить на канал).

Чтобы ответить на ваш вопрос из комментария: go run и go test не являются должен достичь того же эффекта. go run выполняет вашу программу, go test выполняет процедуры, которые проверяют ваш код. Эти команды выполняют две разные программы.

Я не уверен, что вы можете обнаружить подобные ошибки (взаимоблокировки) с помощью тестов.

Редактировать: go test ожидает завершения теста sh ( Вы можете настроить как долго с опцией -timeout d). Поэтому я предполагаю, что он порождает программу, ожидающую истечения срока действия timer.Timer, поэтому нет тупика (всегда есть одна программа, которая может быть выполнена).

Edit2: Try эта программа:

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()
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...