我是golang的新手。嘗試學習并發。使用通道分叉后的連接點的概念現在困擾著我。這是我的代碼
package main
import (
"fmt"
"net/http"
"github.com/vijay-psg587/golang/golang-srv/src/modules/test-dir-DONT-USE/concurrency/status-checker/models"
)
func printChannelData(str string, url chan models.URLCheckerModel) {
fmt.Println("Data in channel is: ", str)
resp, err := http.Get(str)
if err != nil {
url <- models.URLCheckerModel{
StatusCode: 500,
URL: str,
Message: err.Error(),
}
} else {
url <- models.URLCheckerModel{
StatusCode: 200,
URL: str,
Message: resp.Status,
}
}
}
func main() {
fmt.Println("Main started...")
links := []string{"http://google.com", "http://golang.org", "http://amazon.com"}
op := make(chan models.URLCheckerModel)
defer close(op)
for i := 0; i < len(links); i {
// call to goroutine
go func(str string) {
printChannelData(str, op)
}(links[i])
}
for data := range op {
fmt.Println("data receveied:", data)
}
fmt.Println("Main ended...")
}
現在,當我執行此操作時,我的 go 函式不會結束。它獲取資料
Main started...
Data in channel is: http://amazon.com
Data in channel is: http://google.com
Data in channel is: http://golang.org
data receveied: {200 http://google.com 200 OK}
data receveied: {200 http://golang.org 200 OK}
data receveied: {200 http://amazon.com 200 OK}
三個 go 例程開始并運行,但它永遠不會結束。根本不會回到主要的 go 例程
現在,如果我做出這樣的改變,(在連接點)
// for data := range op {
// fmt.Println("data receveied:", data)
// }
fmt.Println("data received:", <-op)
fmt.Println("data received:", <-op)
fmt.Println("data received:", <-op)
而不是 for 回圈,然后我得到資料并且主要的 go 例程也結束了。不知道我在哪里犯了錯誤以及為什么從未呼叫過主例程
Main started...
Data in channel is: http://amazon.com
Data in channel is: http://golang.org
Data in channel is: http://google.com
data received: {200 http://google.com 200 OK}
data received: {200 http://golang.org 200 OK}
data received: {200 http://amazon.com 200 OK}
Main ended...
uj5u.com熱心網友回復:
在 Go 中使用for range
通道時,迭代器將繼續阻塞,直到底層通道關閉。
x := make(chan int, 2)
x <- 1
x <- 2
close(x) // Without this, the following loop will never stop
for i := range x {
print(i)
}
在您的情況下, usingdefer
意味著只有在父方法退出后(即回圈完成后)才會關閉通道,這會導致死鎖。
通常,在使用扇出/扇入模型時,您將使用類似的東西sync.WaitGroup
來協調關閉通道/繼續。
在您的情況下,這可能類似于以下內容:
links := []string{"http://google.com", "http://golang.org", "http://amazon.com"}
op := make(chan models.URLCheckerModel)
var wg sync.WaitGroup
for i := 0; i < len(links); i {
wg.Add(1)
go func(str string) {
defer wg.Done()
printChannelData(str, op)
}(links[i])
}
go func() {
wg.Wait()
close(op)
}()
for data := range op {
fmt.Println("data receveied:", data)
}
uj5u.com熱心網友回復:
您的頻道是無緩沖的,因此您在 main.go 中的代碼將無限運行,等待發生某些事情,因為代碼無法繼續,因為無緩沖的頻道是同步的,在該頻道上收聽的任何人都只能在收到時停止收聽一個值(在這種情況下,由于有時請求到達或永遠不會到達需要時間,因此代碼將在 main.go 中無限運行)。
你有兩個選擇:
或者您將頻道的緩沖區定義為您的 URL 串列的大小,并使您的代碼真正異步和并發。
op := make(chan models.URLCheckerModel, len(links))
或者您必須創建多個頻道,每個 URL 一個,以便在處理每個頻道時,加載值并在搜索方法中關閉您的頻道。
links := []string{"http://google.com", "http://golang.org", "http://amazon.com"} for i := 0; i < len(links); i { // call to goroutine op := make(chan models.URLCheckerModel) go func(str string) { printChannelData(str, op) fmt.Println(<-op) }(links[i]) } func printChannelData(str string, url chan models.URLCheckerModel) { fmt.Println("Data in channel is: ", str) resp, err := http.Get(str) if err != nil { url <- models.URLCheckerModel{ StatusCode: 500, URL: str, Message: err.Error(), } } else { url <- models.URLCheckerModel{ StatusCode: 200, URL: str, Message: resp.Status, } } close(url) }
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/466882.html
上一篇:不在主包中的Go檔案未運行