我正在学习Golang,但遇到了一些困难。我已经研究过Google,但没有任何进展。
我编写了一个代码,该代码通过多个服务器的ICMP检查RTT。
它具有以下结构:
type Server struct {
id uint
ip string
rtt time.Duration
}
它有一个包含多个服务器的切片(是数组吗?)。
对于此片中的每个服务器,我调用getRTT函数,该函数返回RTT,然后将其存储在Server.rtt
中,因为在for循环之后,我要打印所有服务器及其各自的RTT。
for _, server := range servers {
server.rtt = getRTT(server.ip) / time.Millisecond
}
fmt.Println(servers)
该问题已同步,因此请一一发送“ ping”。我想使这个异步,并限制最大的goroutines。例如:一次拨打20 getRTT。
我正在阅读有关goroutine,maxgroup,channel的信息,但到目前为止我还没有。
答案 0 :(得分:1)
Go中有许多模式可以为goroutine设置阈值。我的最爱之一是使用管道。在管道模式中,您将创建一组正在运行的goroutine,并将结构作为工作传递给它们。
以下代码是管道的说明性示例。请注意,您必须提供一种同步方式来等待goroutine终止,例如使用sync.WaitGroup。
package main
import "fmt"
type handler struct {
workStream chan int
}
func (h handler) handle() {
for w := range h.workStream {
fmt.Printf("do some work with %d\n", w)
}
}
func main() {
h := handler{
workStream: make(chan int),
}
// run goroutines as much as you want
for i := 0; i < 5; i++ {
go h.handle()
}
for i := 0; i < 1000; i++ {
h.workStream <- i
}
close(h.workStream) // by closing this channel all goroutines all killed
// TODO: wait for all goroutines to die
}
答案 1 :(得分:1)
启动20个goroutine来完成工作。使用通道将工作分配给这些goroutine。等待goroutines完成。
// c is channel for sending *Server values to worker goroutines.
c := make(chan *Server)
// Start worker goroutines. Each goroutine receives
// values from c in a loop. The loop breaks when c
// is closed.
var wg sync.WaitGroup
for i := 0; i < 20; i++ {
wg.Add(1)
go func() {
for server := range c {
server.rtt = getRTT(server.ip)
}
wg.Done()
}()
}
// Feed work to the goroutines.
for _, server := range servers {
c <- server
}
// Close channel to cause workers to break out of
// for loop.
close(c)
// Wait for the workers to complete.
wg.Wait()
fmt.Println(servers)
答案 2 :(得分:0)
我喜欢为此使用一个简单的计数信号量,并与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}]