#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!"
}
Комментарии:
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!"
}