Почему значение, переданное в канал, не распечатывается fmt.Println?

#go #pointers #channel

#Вперед #указатели #канал

Вопрос:

 func main() {
    links := []string{
        "http://google.com",
        "http://amazon.com",
        "http://golang.org",
        "http://yahoo.com",
        "http://ebay.com",
    }

    c := make(chan string)

    for _, link := range links {
        testRequest(link, c)
    }
    msg := <-c
    fmt.Println(msg)
}
func testRequest(s string, c chan string) {
    _, err := http.Get(s)
    if err != nil {
        fmt.Println(s, "Is down presently")
        c <- "Something might be down"
        return
    }
    fmt.Println(s, "Is working perfectly")
    c <- "Working great!"
}
  

Предполагается, что каналы являются ссылочным типом, и по какой-то причине функция ничего не передает каналу, потому что каждый раз, когда я запускаю код, он выводит первую строку, как и ожидалось, но программа не прекращает работу, а также не выполняет fmt.Println(channel) , поэтому я предполагаю, что никакое значение не передается вканал, каким он должен быть, есть ли причина для этого?

Комментарии:

1. Проблема здесь в том, что программа не завершается и не печатает значение из канала @MuffinTop

2. Упс, неправильно понял. Программа блокирует отправку в канал c . Связь по небуферизованному каналу c не продолжается до тех пор, пока отправитель и получатель не будут готовы. Все отправки выполняются перед единственным получением.

Ответ №1:

При небуферизованном канале запись в testRequests() будет заблокирована до того, как вы перейдете к чтению из канала в main() . Вы зашли в тупик. Обычно вы должны получить сообщение об ошибке, обычно go выясняет, когда все программы заблокированы. Не уверен, почему вы этого не делаете.

Вероятно, вы хотите запустить testRequests() в другой подпрограмме:

 package main

import (
    "fmt"
    "net/http"
)

func main() {
    links := []string{
            "http://google.com",
            "http://amazon.com",
            "http://golang.org",
            "http://yahoo.com",
            "http://ebay.com",
    }

    c := make(chan string)

    go func() {
            for _, link := range links {
                    testRequest(link, c)
            }
            close(c)
    }()
    for msg := range c {
            fmt.Println(msg)
    }
    fmt.Println("Done handling request")
}

func testRequest(s string, c chan string) {
    _, err := http.Get(s)
    if err != nil {
            fmt.Println(s, "Is down presently")
            c <- "Something might be down"
            return
    }
    fmt.Println(s, "Is working perfectly")
    c <- "Working great!"
}
  

https://play.golang.org/p/g9X1h_NNJAB

Комментарии:

1. Когда вы делаете HTTP-запрос, HTTP-транспорт создает одну или две подпрограммы для выполнения домашних задач (обычно спящих, но не бесконечно заблокированных), и этого достаточно, чтобы детектор взаимоблокировки поверил, что все в порядке. Это далеко не надежно 🙂

2. Ах, в этом есть тонна смысла. В тех местах, где я видел панику, у меня не было никаких HTTP-запросов. Спасибо @hobbs!

Ответ №2:

Ваша программа застряла после первого цикла for, отправитель пытается отправить на канал, но получатель может получать только после завершения цикла

 //This loop will blocks until finished
for _, link := range links {
    testRequest(link, c) // Try to send, receiver can't receive
}

//Until above loop finishs, this never excutes
msg := <-c
mt.Println(msg)
  

Запустите цикл отправителя с go помощью so receiver loop, который может вызвать исключение, но вам нужно предотвратить выход из основной программы, пока все работы не будут завершены.

 func main() {
    links := []string{
        "http://google.com",
        "http://amazon.com",
        "http://yahoo.com",
        "http://ebay.com",
    }

    c := make(chan string)

    // This code will not blocks
    go func() {
        for _, link := range links {
            testRequest(link, c)
        }
    }()

    // Above code doesn't block, this code can excutes
    for {
        msg := <-c
        fmt.Println(msg)
    }
}

func testRequest(s string, c chan string) {
    _, err := http.Get(s)
    if err != nil {
        fmt.Println(s, "Is down presently")
        c <- "Something might be down"
        return
    }
    fmt.Println(s, "Is working perfectly")
    c <- "Working great!"
}