我是goroutines,频道和喜欢的新手,如果这看似微不足道,那么道歉。
我写了以下代码:
for _, h := range hosts {
go func() {
httpClient := cleanhttp.DefaultPooledClient()
// format the URL with the passed host and por
url := fmt.Sprintf("https://%s:%v", h.Name, h.Port)
// create a vault client
client, err := api.NewClient(&api.Config{Address: url, HttpClient: httpClient})
if err != nil {
panic(err)
}
// get the current status
status := v.VaultStatus(client)
// send the status to a channel
s <- strconv.FormatBool(status.Ready)
}()
// assign the value of channel to a var
cs := <-s
// print it
fmt.Printf("Host: %s Status: %s\n", h.Name, cs)
}
},
这个想法很简单,它需要一个主机列表,然后使用Golang Vault API来确定当前状态。我很高兴它有效。
我想做的是确保这些操作并行发生。当我运行以下代码时,我得到如下结果:
host: Host1: status: true
host: Host2: status: false
host: Host3: status: true
host: Host4: status: true
这里的问题是这些主机总是以相同的顺序返回。我认为goroutine根本不是并行执行的,因为它们似乎是一个接一个地操作,然后每次都以相同的顺序打印。
代码是否按照我的想法行事?我如何知道这个goroutine并行运行?
答案 0 :(得分:3)
您一次只运行一个goroutine,因为主循环正在等待通道,然后继续循环的下一次迭代。相反,您应该在所有goroutine启动后等待for循环之外的通道上的结果。顺便说一句,您还需要在频道上发送识别主机的内容。
顺便说一句,你的goroutine功能存在潜在的问题。您正在使用变量h
,每次循环都会被主goroutine更改,因此您不会真正了解您在其他goroutine中获得的内容(假设你照顾我上面提到的问题,以便goroutines并行运行)。您应该将它作为参数传递给goroutine函数(或者您可以在for循环中创建一个不同的变量并为其赋值h
并在函数内部使用该变量),而不是直接引用该变量。
尝试这样做:
var wg sync.WaitGroup
for _, h := range hosts {
h := h // create local copy of loop var
wg.Add(1)
go func() {
defer wg.Done()
httpClient := cleanhttp.DefaultPooledClient()
// format the URL with the passed host and por
url := fmt.Sprintf("https://%s:%v", h.Name, h.Port)
// create a vault client
client, err := api.NewClient(&api.Config{Address: url, HttpClient: httpClient})
if err != nil {
panic(err)
}
// get the current status
status := v.VaultStatus(client)
// print it
fmt.Printf("Host: %s Status: %v\n", h.Name, status.Ready)
}()
}
wg.Wait()
答案 1 :(得分:1)
一般来说,如果你想知道goroutines是否并行运行,你应该trace the scheduler。
答案 2 :(得分:1)
假设您有:
type Status struct {
URL string
Ready bool
}
s
初始化为:
s := make(chan Status)
然后你可以写:
var wg sync.WaitGroup
for _, h := range hosts {
h := h
wg.Add(1)
go func() {
defer wg.Done()
httpClient := cleanhttp.DefaultPooledClient()
// format the URL with the passed host and por
url := fmt.Sprintf("https://%s:%v", h.Name, h.Port)
// create a vault client
client, err := api.NewClient(&api.Config{Address: url, HttpClient: httpClient})
if err != nil {
panic(err)
}
// get the current status
status := v.VaultStatus(client)
// send the status to the channel
s <- Status{url, status.Ready}
}()
}
// this goroutine's job is closing s after all above goroutines have finished
go func() {
wg.Wait()
close(s) // so the following loop does not block after reading all statuses
}()
for st := range s {
// here you could collect all statuses in a []Status or something
// for simplicity, just print them as you did
fmt.Printf("Host: %s Status: %v\n", st.URL, st.Ready)
}