当前位置: 首页 > 面试题库 >

goroutine的订购结果

谢典
2023-03-14
问题内容

下面是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}]


 类似资料:
  • 我被一个简单的任务困住了。我只需要这通电话的结果 其中,是一个模型。我试过这个 但它不起作用。从表中获取所有数据并对其进行排序的更好方法是什么?

  • 问题内容: 我有一个与数据库对话的servlet,然后返回一个有序(按时间排序)对象的列表。在servlet部分,我有 从日志中,我可以看到数据库以正确的顺序返回了User对象。 在前端,我有 但是顺序改变了。 我只在返回的列表很大(超过130个用户)时才注意到这一点。 我尝试使用Firebug进行调试,Firebug中的“响应选项卡”显示列表的顺序与servlet中的日志不同。 我做错了什么吗?

  • 问题内容: 我有一个叫做 School 的模型,它有很多 学生 。 这是我模型中的代码: 我在控制器中使用此代码让所有学生: 并在视图中: 现在,我想按表中的某些字段对 学生 进行排序。我怎样才能做到这一点? 问题答案: 您可以通过几种方法实现这一目标:

  • 我是Flink的新手,我试图理解Flink是如何在其的并行抽象中命令调用。考虑这个产生部分和的流的例子: 我希望它的输出是流:。事实上,就在这里。 是否可以安全地假设这种情况始终存在,尤其是在从具有大量并行性的源读取数据时?

  • 问题内容: 我有一个这样的表: 我想创建一个有序的表单,如下所示: 在数据库中,有很多书,而不仅仅是一本书。 有没有办法以这种方式对查询“ SELECT”进行排序?这只是一个表面问题,不需要做多维数组之类的事情,因为我可以在标签上贴上它们的类型,然后根据类型更改它们的外观。但是我需要以正确的顺序查找查询。 PD:对不起,我的英语:S 问题答案: 不要以为数据库是个好主意。查询将很难。Imo更好-您

  • 问题内容: 在Java中,是否有一个对象的作用类似于用于存储和访问键/值对的Map,但是可以返回键的有序列表和值的有序列表,从而使键和值列表的顺序相同? 因此,按照代码进行解释,我正在寻找某种行为,就像我的虚拟OrderedMap: 问题答案: 该SortedMap的接口(与实施TreeMap的)应该是你的朋友。 该接口具有以下方法: keySet() 它以升序返回一组键 values() 它以对