我喜欢为此使用一个简单的计数信号量,并结合一个 sync.WaitGroup 以确保按照@Parham Alvani 的建议完成。 (注意@Parham Alvani 的解决方案至少和这个一样正确)
(一些解释 - 我们用缓冲区创建一个通道 - 缓冲区大小变成了 goroutine 允许并发执行的数量。每个 goroutine 将一些东西放入通道中,然后将其读回。在下面的代码的情况下,第五次,goroutine 被阻塞添加到通道,直到另一个 goroutine 从通道中取出一些东西。)
我还让“getRTT”函数在指向服务器的指针上工作,因为我们在这里修改接收器。
这里的游乐场:
https://play.golang.org/p/8Rmp0kHoNFB
package main
import (
"fmt"
"time"
"sync"
"math/rand"
)
type Server struct {
id uint
ip string
rtt time.Duration
}
func (s *Server) setRTT() {
fmt.Printf("setting rtt for id %d\n", s.id)
// do something that takes a while
sleepyTime := time.Second * time.Duration(rand.Intn(5))
time.Sleep(sleepyTime)
s.rtt = sleepyTime
}
func main() {
servers := []Server{
{1,"10.10.10.0",0},
{2,"10.10.10.1",0},
{3,"10.10.10.2",0},
{4,"10.10.10.3",0},
{5,"10.10.10.4",0},
{6,"10.10.10.5",0},
{7,"10.10.10.0",0},
{8,"10.10.10.1",0},
{9,"10.10.10.2",0},
{10,"10.10.10.3",0},
{11,"10.10.10.4",0},
{12,"10.10.10.5",0},
{13,"10.10.10.0",0},
{14,"10.10.10.1",0},
{15,"10.10.10.2",0},
{16,"10.10.10.3",0},
}
semaphore := make(chan struct{}, 4) // limit concurrency simply, you likely want a larger number than 4 here
var wg sync.WaitGroup // necessary to ensure we complete everything - otherwise main will exit before we are done
wg.Add(len(servers))
for i := range servers {
go func(s *Server) {
defer wg.Done()
semaphore <- struct{}{} // put something in channel, will block when > 4
defer func() { <-semaphore }() // remove something from channel as this goroutine completes, allowing another goroutine to continue
s.setRTT()
}(&servers[i])
}
wg.Wait() // wait for it!
fmt.Println(servers)
}
示例输出:
setting rtt for id 16
setting rtt for id 1
setting rtt for id 2
setting rtt for id 3
setting rtt for id 4
setting rtt for id 5
setting rtt for id 6
setting rtt for id 7
setting rtt for id 8
setting rtt for id 9
setting rtt for id 10
setting rtt for id 11
setting rtt for id 12
setting rtt for id 13
setting rtt for id 14
setting rtt for id 15
[{1 10.10.10.0 2000000000} {2 10.10.10.1 2000000000} {3 10.10.10.2 4000000000} {4 10.10.10.3 1000000000} {5 10.10.10.4 3000000000} {6 10.10.10.5 0} {7 10.10.10.0 0} {8 10.10.10.1 1000000000} {9 10.10.10.2 0} {10 10.10.10.3 4000000000} {11 10.10.10.4 1000000000} {12 10.10.10.5 2000000000} {13 10.10.10.0 4000000000} {14 10.10.10.1 3000000000} {15 10.10.10.2 4000000000} {16 10.10.10.3 1000000000}]