简体   繁体   English

在 Golang 中,如何使用 channel 处理多个 goroutine

[英]In Golang, how to handle many goroutines with channel

I'm thinking start 1000 goroutines at the same time using for loop in Golang.我想在 Golang 中使用 for 循环同时启动 1000 个 goroutine。
The problem is: I have to make sure that every goroutine has been executed.问题是:我必须确保每个 goroutine 都已执行。
Is it possible using channels to help me make sure of that?是否可以使用渠道来帮助我确定这一点?

The structure is kinda like this:结构有点像这样:

func main {
    for i ... {
        go ...
        ch?
    ch?
}

As @Andy mentioned You can use sync.WaitGroup to achieve this.正如@Andy 提到的,您可以使用sync.WaitGroup来实现这一点。 Below is an example.下面是一个例子。 Hope the code is self-explanatory.希望代码是不言自明的。

package main

import (
    "fmt"
    "sync"
    "time"
)

func dosomething(millisecs int64, wg *sync.WaitGroup) {
    defer wg.Done()
    duration := time.Duration(millisecs) * time.Millisecond
    time.Sleep(duration)
    fmt.Println("Function in background, duration:", duration)
}

func main() {
    arr := []int64{200, 400, 150, 600}
    var wg sync.WaitGroup
    for _, n := range arr {
     wg.Add(1)
     go dosomething(n, &wg)
    }
    wg.Wait()
    fmt.Println("Done")
}

I would suggest that you follow a pattern.我建议你遵循一个模式。 Concurrency and Channel is Good but if you use it in a bad way, your program might became even slower than expected. Concurrency 和 Channel 是好的,但是如果您以不好的方式使用它,您的程序可能会变得比预期的更慢。 The simple way to handle multiple go-routine and channel is by a worker pool pattern.处理多个 go-routine 和 channel 的简单方法是通过工作池模式。

Take a close look at the code below仔细看看下面的代码

// In this example we'll look at how to implement
// a _worker pool_ using goroutines and channels.

package main

import "fmt"
import "time"

// Here's the worker, of which we'll run several
// concurrent instances. These workers will receive
// work on the `jobs` channel and send the corresponding
// results on `results`. We'll sleep a second per job to
// simulate an expensive task.
func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        fmt.Println("worker", id, "started  job", j)
        time.Sleep(time.Second)
        fmt.Println("worker", id, "finished job", j)
        results <- j * 2
    }
}

func main() {

    // In order to use our pool of workers we need to send
    // them work and collect their results. We make 2
    // channels for this.
    jobs := make(chan int, 100)
    results := make(chan int, 100)

    // This starts up 3 workers, initially blocked
    // because there are no jobs yet.
    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }

    // Here we send 5 `jobs` and then `close` that
    // channel to indicate that's all the work we have.
    for j := 1; j <= 5; j++ {
        jobs <- j
    }
    close(jobs)

    // Finally we collect all the results of the work.
    for a := 1; a <= 5; a++ {
        <-results
    }
}

This simple example is taken from here .这个简单的例子取自这里 Also the results channel can help you keep track of all the go routines executing the jobs including failure notice.此外, results通道可以帮助您跟踪执行作业的所有 go 例程,包括失败通知。

To make sure the goroutines are done and collect the results, try this example:要确保 goroutine 完成并收集结果,请尝试以下示例:

package main

import (
    "fmt"
)

const max = 1000

func main() {
    for i := 1; i <= max; i++ {
        go f(i)
    }

    sum := 0
    for i := 1; i <= max; i++ {
        sum += <-ch
    }

    fmt.Println(sum) // 500500
}

func f(n int) {
    // do some job here and return the result:
    ch <- n
}

var ch = make(chan int, max)

In order to wait for 1000 goroutines to finish, try this example:为了等待 1000 个 goroutines 完成,试试这个例子:

package main

import (
    "fmt"
    "sync"
)

func main() {
    wg := &sync.WaitGroup{}

    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go f(wg, i)
    }

    wg.Wait()
    fmt.Println("Done.")
}

func f(wg *sync.WaitGroup, n int) {
    defer wg.Done()
    fmt.Print(n, " ")
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM