创建goroutine并设置最大goroutine

时间:2019-06-25 02:51:53

标签: go

我正在学习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的信息,但到目前为止我还没有。

3 个答案:

答案 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}]