Just realized what you meant about buffered channels. I'm wrong, and sorry for the confusion.
+1 to your original solution (combined with setting channels to nil). Diane Looney On Tue, Dec 18, 2018 at 11:31 AM Chris Burkert <burkert.ch...@gmail.com> wrote: > Hello Ian, all, > yes, the workers generate multiple results. I was able to use your > proposal with the waiting goroutine which closes the channel. Unfortunately > my initial minimal example was not so minimal. It is a little more > complicated, as I have multiple "result" channels with different types and > I don't know how many values I get. So I can't just range over one channel > but instead use select with the ok from "val, ok := <-channel" to count the > closed channels which finally ends the loop. Below is what I came up with > (using Johns approach to run it multiple times) and it seems to be > deterministic. > Many thanks! > PS: with buffered channels I have to disable closed channels with "channel > = nil" to make it work. > > package main > > import ( > "fmt" > "sync" > ) > > func do(fc chan<- int, rc chan<- string) { > fc <- 42 > fc <- 43 > rc <- "foo" > } > > func main() { > w := 4 > r := 100000 > n := 0 > for i := 0; i < r; i++ { > n = n + run(w) > } > fmt.Printf("Got %d, expected %d\n", n, 3*w*r) > } > > func run(worker int) int { > fc := make(chan int) > rc := make(chan string) > var wg sync.WaitGroup > wg.Add(worker) > for i := 0; i < worker; i++ { > go func() { > defer wg.Done() > do(fc, rc) > }() > } > go func() { > wg.Wait() > close(fc) > close(rc) > }() > n := 0 > closed := 0 > for closed < 2 { > select { > case _, ok := <-fc: > if ok { > n++ > } else { > closed++ > } > case _, ok := <-rc: > if ok { > n++ > } else { > closed++ > } > } > } > return n > } > > Am Di., 18. Dez. 2018 um 15:50 Uhr schrieb Ian Lance Taylor < > i...@golang.org>: > >> On Tue, Dec 18, 2018 at 5:35 AM Chris Burkert <burkert.ch...@gmail.com> >> wrote: >> > >> > I have a couple of goroutines sending multiple results over a channel - >> a simple fan-in. They signal the completion on a done channel. Main selects >> on the results and done channel in parallel. As the select is random main >> sometimes misses to select the last result. What would be the idiomatic way >> to prevent this and completely drain the result channel? >> > >> > Here is a minmal example which sometimes prints one 0 but should always >> print two of them: >> > >> > package main >> > >> > import ( >> > "fmt" >> > ) >> > >> > func do(rc chan<- int, dc chan<- bool) { >> > rc <- 0 >> > dc <- true >> > } >> > >> > func main() { >> > worker := 2 >> > rc := make(chan int, worker) >> > done := 0 >> > dc := make(chan bool, worker) >> > for i := 0; i < worker; i++ { >> > go do(rc, dc) >> > } >> > for done < worker { >> > select { >> > case <-dc: >> > done++ >> > case r := <-rc: >> > fmt.Println(r) >> > } >> > } >> > } >> >> >> I assume the workers can generate multiple results, as otherwise the >> done marker seems pointless. In general the simplest way to signal >> completion on a channel is to call close. The simplest way to call >> close on a fan-in is to have another goroutine that waits for the >> other goroutines and closes the channel. That might look like >> >> package main >> >> import ( >> "fmt" >> "sync" >> ) >> >> func do(rc chan<- int) { >> rc <- 0 >> } >> >> func main() { >> worker := 2 >> rc := make(chan int, worker) >> var wg sync.WaitGroup >> wg.Add(worker) >> for i := 0; i < worker; i++ { >> go func() { >> defer wg.Done() >> do(rc) >> }() >> } >> go func() { >> wg.Wait() >> close(rc) >> }() >> for r := range rc { >> fmt.Println(r) >> } >> } >> >> Ian >> > -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.