0

I have two functions, What I would like to do is have a channel outside these two functions and have the first run in a go routine and update the channel and then the second function should read the items in the channel as they come in and do something else. When all the items in the channel are finished the go routines should exit gracefully

Could someone ELI5 how I can get two go routines reading from the same channel ? is that even possible ?

Something like the below...


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

The above deadlocks but is the simplest way I can explain without pasting in a lot of code.

2
  • 1
    You don't need to pass pointers to a channel. Pass the channel itself. Commented Dec 11, 2019 at 22:17
  • 1
    "as UpdatePeople is writing to it in a separate go routine" - UpdatePeople doesn't do anything with the channel. That's why the read operation blocks the main goroutine (there's nothing in the channel) Commented Dec 11, 2019 at 22:19

1 Answer 1

2

As Sergio pointed out, the Main goroutine is blocking because its waiting read from the psns channel, but nothing is writing to it. There's a good piece of advice when writing Go to only write synchronous functions, and another that the function responsible for creating a channel controls when it is closed. As such, I've restructured what you wrote a little with these in mind: https://play.golang.org/p/vicGN40pGVQ. This program will slowly find Person objects, send them over the channel, and write each Person as it goes. Let us know if your use-case differs :) Hope that helps.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you icio. That's so simple and elegant. This make a lot of sense and almost works for my use case. using your example, if I need to wrap the gofunc with FindPeople in a for loop, I think I end up with with a panic. do I need to then make an slice of chans for each go routine ?
Yes, if you try to close the channel multiple times the program will panic. If you want to launch multiple independent FindPeople, we need to wait for them all to complete before closing our chan people. We can use a sync.WaitGroup for this as so: play.golang.org/p/0aZPqhZ9W0O
wow thanks that really helps me "get it" :-) Finally..would it be crazy to then want to put WritePerson(p) into a go routine as well ? ultimately i'm looking for speed plus the ability to run both those as go routines in the background but Im not sure if that's the right way to do things.
You could, but its not guaranteed to make things faster. If you're writing to a database, a good starting point might be to think about how many concurrent writes your system would support - perhaps related to the number of connections your process can open to the server. My last example would be a single concurrent write per process. If we were to support up to 3 writes simultaneously we might use the same worker pattern as we did for the finders: play.golang.org/p/B8eOzko2Pb2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.