Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Concurrency 等待n个goroutine的终止_Concurrency_Go_Channel_Coroutine_Goroutine - Fatal编程技术网

Concurrency 等待n个goroutine的终止

Concurrency 等待n个goroutine的终止,concurrency,go,channel,coroutine,goroutine,Concurrency,Go,Channel,Coroutine,Goroutine,我需要开始大量的goroutines并等待它们的终止。直观的方法似乎是使用一个通道来等待所有这些操作完成: package main type Object struct { //data } func (obj *Object) Update(channel chan int) { //update data channel <- 1 return } func main() { channel := make(chan int, n)

我需要开始大量的goroutines并等待它们的终止。直观的方法似乎是使用一个通道来等待所有这些操作完成:

package main

type Object struct {
    //data
}

func (obj *Object) Update(channel chan int) {
    //update data
    channel <- 1
    return
}

func main() {

    channel := make(chan int, n)
    list := make([]Object, n, m)
    for {
        for _, object := range list {
            go object.Update(channel)
        }
        for i := 0; i < n; i++ {
            <-channel
        }
        //now everything has been updated. start again
    }
}
主程序包
类型对象结构{
//资料
}
func(obj*对象)更新(通道内部){
//更新数据

channel这项任务并不简单,编写错误的任务非常容易。我建议使用stdlib中现成的解决方案。引用链接:

WaitGroup等待goroutine集合完成。主goroutine调用Add可设置要等待的goroutine数。然后,每个goroutine运行并在完成时完成调用。同时,wait可用于阻止,直到所有goroutine完成

我已将其用作此问题的解决方案。翻译您当前的代码,并使用一些日志来明确发生了什么:

package main

import "sync"
import "fmt"
import "time"

type Object struct {
    //data
}

func (obj *Object) Update(wg *sync.WaitGroup) {
    //update data
    time.Sleep(time.Second)
    fmt.Println("Update done")
    wg.Done()
    return
}

func main() {
    var wg sync.WaitGroup
    list := make([]Object, 5)
    for {
        for _, object := range list {
            wg.Add(1)
            go object.Update(&wg)
        }
        //now everything has been updated. start again
        wg.Wait()
        fmt.Println("Group done")
    }
}

@tjameson在解释如何使用
WaitGroup
以及如何将对
WaitGroup
对象的引用传递给函数时做了大量工作。我对他的示例所做的一个更改是在
Done
完成后利用
defer
。我认为这是
defer ws.Done()
应该是函数中的第一条语句

我喜欢
WaitGroup
的简单性。但是,我不喜欢我们需要将引用传递给goroutine,因为这意味着并发逻辑将与您的业务逻辑混合

所以我提出了这个通用函数来解决这个问题:

// Parallelize parallelizes the function calls
func Parallelize(functions ...func()) {
    var waitGroup sync.WaitGroup
    waitGroup.Add(len(functions))

    defer waitGroup.Wait()

    for _, function := range functions {
        go func(copy func()) {
            defer waitGroup.Done()
            copy()
        }(function)
    }
}
所以你的例子可以这样解决:

type Object struct {
    //data
}

func (obj *Object) Update() {
    //update data
    time.Sleep(time.Second)
    fmt.Println("Update done")
    return
}

func main() {
    functions := []func(){}
    list := make([]Object, 5)
    for _, object := range list {
        function := func(obj Object){ object.Update() }(object)
        functions = append(functions, function)
    }

    Parallelize(functions...)        

    fmt.Println("Group done")
}

如果你想使用它,你可以在这里找到它

你可以在每次迭代中重新分配它,但是你可能想看看。tjameson,谢谢你的快速帮助。看起来真的很好。你可能想把它作为一个答案。完成了,有一个例子=很好的答案的可能重复!我可能会把
延迟工作组。完成()
更新开始时
虽然只是为了防止函数在将来某个时间增长并获得早期返回。或者是为了防止出现恐慌或其他情况。如果要等待的goroutine的数量事先未知?@Dfr在启动每个goroutine时增加计数器,因此此解决方案仍然是最佳的解决方案r当您不知道要开始的goroutine的数量时。