【问题标题】:golang pass struct between two goroutines concurrentlygolang 在两个 goroutine 之间同时传递结构
【发布时间】:2019-12-11 22:13:47
【问题描述】:

我有两个函数,我想做的是在这两个函数之外有一个通道,第一个在 go 例程中运行并更新通道,然后第二个函数应该在通道中的项目到来时读取它们进去做点别的。当通道中的所有项目都完成后,go 例程应该优雅地退出

有人 ELI5 可以让我从同一个频道读取两个 goroutine 吗?这甚至可能吗?

类似下面的...


package main

import (
    "fmt"
)

type Person struct {
    index int
    name  string
    age   int
}

func UpdatePeople(psn *chan Person, grNo int) {

    for i := 0; i < 5; i++ {
        psn := Person{
            index: 1,
            name:  "Shaun",
            age:   23,
        }
        fmt.Printf("Person: %v --- GoRoutineNumber: %v\n", psn, grNo)
    }

}

func WritePeople(psn *chan Person) {

    for i := 0; i < 5; i++ {
        psn := Person{
            index: 1,
            name:  "Shaun",
            age:   23,
        }
        fmt.Println("Writing People to DB", psn)
    }

}

func main() {

    //make channel of Person struct
    psnChan := make(chan Person)

    //I have a variable length in my program so lets say it's 6 in this case

    for i := 0; i < 6; i++ {

        /// I want to start a go routine here that writes to pointer of psnChan
        go UpdatePeople(&psnChan, i)

    }

    // I then want to read in from the channel as UpdatePeople is writing to it in a separate go routine
    for {

        _, received := <-psnChan
        if received == false {
            fmt.Println("Break out of 2nd loop")
            close(psnChan)
            break
        } else {

          go    WritePeople(&psnChan)

        }

    }
    fmt.Println("Finished")
}



https://play.golang.org/p/ExJf3lY0VV8

上面的死锁是我不用粘贴大量代码就能解释的最简单的方法。

【问题讨论】:

  • 您不需要将指针传递给通道。传递通道本身。
  • “因为 UpdatePeople 在单独的 go 例程中写入它” - UpdatePeople 不对频道做任何事情。这就是读操作阻塞主 goroutine 的原因(通道中什么都没有)

标签: go struct concurrency goroutine


【解决方案1】:

正如 Sergio 指出的那样,Main goroutine 正在阻塞,因为它等待从 psns 通道读取,但没有任何东西写入它。在编写 Go 时有一个很好的建议,即只编写同步函数,另一个建议是负责创建通道的函数在关闭时进行控制。因此,我考虑到这些内容,对您写的内容进行了一些重组:https://play.golang.org/p/vicGN40pGVQ。该程序将慢慢找到 Person 对象,通过通道发送它们,并在执行过程中写入每个 Person。如果您的用例不同,请告诉我们:) 希望对您有所帮助。

【讨论】:

  • 谢谢 icio。这是如此简单和优雅。这很有意义,几乎适用于我的用例。使用您的示例,如果我需要将 gofunc 与 FindPeople 包装在 for 循环中,我想我最终会感到恐慌。然后我需要为每个 goroutine 制作一片 chans 吗?
  • 是的,如果您尝试多次关闭频道,程序将会崩溃。如果要启动多个独立的 FindPeople,我们需要等待它们全部完成,然后再关闭我们的 chan 人员。我们可以为此使用 sync.WaitGroup:play.golang.org/p/0aZPqhZ9W0O
  • 哇,谢谢,这真的帮助我“得到它”:-) 最后..然后想把 WritePerson(p) 也放入一个 go 例程中会很疯狂吗?最终我正在寻找速度以及在后台运行这两个程序的能力,但我不确定这是否是正确的做事方式。
  • 你可以,但不能保证让事情变得更快。如果您正在写入数据库,一个好的起点可能是考虑您的系统将支持多少并发写入 - 可能与您的进程可以打开到服务器的连接数有关。我的最后一个示例是每个进程一次并发写入。如果我们要同时支持多达 3 次写入,我们可能会使用与查找器相同的工作模式:play.golang.org/p/B8eOzko2Pb2
猜你喜欢
  • 2014-11-14
  • 1970-01-01
  • 1970-01-01
  • 2015-08-31
  • 1970-01-01
  • 2015-06-10
  • 2017-01-05
  • 2016-09-19
  • 1970-01-01
相关资源
最近更新 更多