如何从以特定顺序执行的N个goroutine中收集值?

下面是Stuff类型的结构。它具有三个整数。A

Number,它Double和它的Power。让我们假设计算给定int列表的double和power是昂贵的计算。

type Stuff struct {

Number int

Double int

Power int

}

func main() {

nums := []int{2, 3, 4} // given numbers

stuff := []Stuff{} // struct of stuff with transformed ints

double := make(chan int)

power := make(chan int)

for _, i := range nums {

go doubleNumber(i, double)

go powerNumber(i, power)

}

// How do I get the values back in the right order?

fmt.Println(stuff)

}

func doubleNumber(i int, c chan int) {

c <- i + i

}

func powerNumber(i int, c chan int) {

c <- i * i

}

的结果fmt.Println(stuff)应与初始化内容相同,例如:

stuff := []Stuff{

{Number: 2, Double: 4, Power: 4}

{Number: 3, Double: 6, Power: 9}

{Number: 4, Double: 8, Power: 16}

}

我知道我可以使用<- double<- power从通道中收集值,但是我不知道什么双/次方属于什么数字。

回答:

Goroutines独立地并行运行,因此,如果没有显式同步,您将无法预测执行和完成顺序。因此,您无法将返回的数字与输入的数字配对。

您可以返回更多数据(例如,输入数字和输出,例如包装在结构中),也可以将指针传递到辅助函数(作为新的goroutine发布),例如*Stuff,让goroutine自己填充计算出的数据Stuff

返回更多数据

我将使用的信道类型chan Pair,其中Pair是:

type Pair struct{ Number, Result int }

因此计算将如下所示:

func doubleNumber(i int, c chan Pair) { c <- Pair{i, i + i} }

func powerNumber(i int, c chan Pair) { c <- Pair{i, i * i} }

我将使用a,map[int]*Stuff因为可收集的数据来自多个渠道(doublepower),并且我想Stuff轻松快捷地找到合适的数据(需要指针,因此我也可以在“地图”中对其进行修改)。

所以主要功能:

nums := []int{2, 3, 4} // given numbers

stuffs := map[int]*Stuff{}

double := make(chan Pair)

power := make(chan Pair)

for _, i := range nums {

go doubleNumber(i, double)

go powerNumber(i, power)

}

// How do I get the values back in the right order?

for i := 0; i < len(nums)*2; i++ {

getStuff := func(number int) *Stuff {

s := stuffs[number]

if s == nil {

s = &Stuff{Number: number}

stuffs[number] = s

}

return s

}

select {

case p := <-double:

getStuff(p.Number).Double = p.Result

case p := <-power:

getStuff(p.Number).Power = p.Result

}

}

for _, v := range nums {

fmt.Printf("%+v\n", stuffs[v])

}

输出(在Go Playground上尝试):

&{Number:2 Double:4 Power:4}

&{Number:3 Double:6 Power:9}

&{Number:4 Double:8 Power:16}

使用指针

从现在开始我们传递*Stuff值,我们可以在Stuff自身中“预填充”输入数字。

但是必须小心,您只能在正确同步的情况下读取/写入值。最简单的方法是等待所有“工人” goroutine完成工作。

var wg = &sync.WaitGroup{}

func main() {

nums := []int{2, 3, 4} // given numbers

stuffs := make([]Stuff, len(nums))

for i, n := range nums {

stuffs[i].Number = n

wg.Add(2)

go doubleNumber(&stuffs[i])

go powerNumber(&stuffs[i])

}

wg.Wait()

fmt.Printf("%+v", stuffs)

}

func doubleNumber(s *Stuff) {

defer wg.Done()

s.Double = s.Number + s.Number

}

func powerNumber(s *Stuff) {

defer wg.Done()

s.Power = s.Number * s.Number

}

输出(在Go Playground上尝试):

[{Number:2 Double:4 Power:4} {Number:3 Double:6 Power:9} {Number:4 Double:8 Power:16}]

以上是 如何从以特定顺序执行的N个goroutine中收集值? 的全部内容, 来源链接: utcz.com/qa/408531.html

回到顶部