0

New to go. I am trying to read a map[int][]string, write the slice of strings into an intermediate channel and then once everything is written, read back all the strings from intermediate channel to another channel and finally read the channel into another goroutine.

I am not able to figure out what is a good non-blocking way to read from the intermediate channel.

package main

import (
    "fmt"
)

func f1(c chan []string, q chan int) {
  // intermediate channel
    ic := make(chan []string, 10)

  hmap := map[int][]string{
    0: []string{"a", "b", "c"},
    1: []string{"d", "e",},
    2: []string{"f", "g", "h"},
  }
  // for every elem in hmap put the values into intermediate channel
    for _, v := range hmap {
       f2(v, ic)
    }

  // everything is in intermediate channel by now
  // read all the []string and concatenate them into a slice in a
  // non-blocking fashion
  var strs []string
  for v := range ic {
    strs = append(strs, v...)
  }
    // strs := <-ic
  fmt.Println(strs)
    select {
  case c <- strs:
    fmt.Println("Received strings.")
  default:
    fmt.Println("did not receive anything.")
  }
    q <- 1
}

func f2(v []string, ic chan []string) {
    select {
    case ic <- v:
        fmt.Println("Sent to intermediate channel:", v)
    default:
        fmt.Println("nothing to send...")
    }
}
func f3(c chan []string) {
    fmt.Println(<-c)
}

func main() {
    c := make(chan []string, 10)
    q := make(chan int)
    go f1(c, q)
    go f3(c)
    fmt.Println(<-q) // to wait for the quit to be set
}

go run main.go to run.

This program goes into deadlock. How can I avoid the deadlock?

1
  • 3
    for v := range ic { this blocks until ic is closed. Commented May 22, 2018 at 0:52

1 Answer 1

1

As @zerkms said in the comment, you need to close the channel when you're done writing to it, or the for v := range ic { will block.

package main

import (
    "fmt"
)

func f1(c chan []string, q chan int) {
    ic := make(chan []string, 10)

    hmap := map[int][]string{
        0: []string{"a", "b", "c"},
        1: []string{"d", "e"},
        2: []string{"f", "g", "h"},
    }
    for _, v := range hmap {
        f2(v, ic)
    }
    // done writing strings, close the channel
    close(ic)
    var strs []string
    for v := range ic {
        strs = append(strs, v...)
    }
    fmt.Println(strs)
    select {
    case c <- strs:
        fmt.Println("Received strings.")
    default:
        fmt.Println("did not receive anything.")
    }
    q <- 1
}

func f2(v []string, ic chan []string) {
    select {
    case ic <- v:
        fmt.Println("Sent to intermediate channel:", v)
    default:
        fmt.Println("nothing to send...")
    }
}
func f3(c chan []string) {
    fmt.Println(<-c)
}

func main() {
    c := make(chan []string, 10)
    q := make(chan int)
    go f1(c, q)
    go f3(c)
    fmt.Println(<-q) // to wait for the quit to be set
}

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

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

2 Comments

Thank you. That is what i was looking for.
Glad you got what you needed. I will add with regards to read back all the strings from intermediate channel to another channel, you might not need a second channel there -- channels are good for communicating between go routines, but if you want to aggregate them afterwards in a single threaded manner, for that I recommend using another string slice, e.g. var strs []string.

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.