1

I want to populate an array of arrays inside a subroutine. I am trying to do this using a channel. I am learning go, so unclear if this is the right way, so please correct me if I am going in the wrong direction, but my code never returns. What am I doing wrong?

var c = make(chan [3][4]string)

var mymap = map[int]string{
    0: "www.foo.com",
    1: "www.bar.com",
    2: "www.baz.com",
    3: "www.faz.com",
}

values := [3][4]string{{"A", "B", "C", "D"}}

var wg sync.WaitGroup
wg.Add(4) // one thread per index, total 4 indexes

for idx, url := range mymap {
    go func(idx int, url string) {
        defer wg.Done()
        values[1][idx] = "someone"
        values[2][idx] = "something"
        c <- values
    }(name, url)
}

wg.Wait()
close(c)
Ufder
  • 527
  • 4
  • 20
  • 1
    Who is reading from channel c? – Burak Serdar Sep 19 '22 at 04:14
  • What is not working? and do update the rest of the code – Inian Sep 19 '22 at 04:42
  • How is `c` declared and with how much capacity ? – selbie Sep 19 '22 at 05:38
  • functions invoked in `defer` only execute after the enclosing function returns. Since you have a line `c <- values` , the enclosing function stops at this line. It will stop once the buffer of the channel is full. In order for the function to proceed you need an independent(go routine) to read from the channel. – whitespace Sep 19 '22 at 09:16
  • Ah, sorry, updated. `var c = make(chan [15][4]string)`. I think I have some more reading to do. Thanks. My ultimate objective is to populate the `values` array. If I don't use Channels, I see that its populated in the routines, but the value does not persist i.e. in the end if I print it out, its empty. – Ufder Sep 19 '22 at 15:23

2 Answers2

2

From code it looks like channel c is not read, and code is stuck there.

This code doesn't need any synchronisation (channel etc.) because each goroutine is working on different part of values, gr1->[xx,0], gr2->[xx,1], gr3-> [xx,2], gr4-> [xx,3].

Just remove the channel c from the code and this should work fine.

Change goroutine code to:

go func(idx int, url string, arr *[3][4]string) {
  defer wg.Done()
  arr[1][idx] = "someone"
  arr[2][idx] = "something"
}(idx, url, &values)
  • Thanks. That is what I started with, but the values don't persist in the Array, hence I started using channels. Perhaps I am missing something. – Ufder Sep 19 '22 at 15:23
  • Fyi: https://stackoverflow.com/questions/54534588/get-responses-from-multiple-go-routines-into-an-array – Ufder Sep 19 '22 at 15:46
  • @Ufder Updated my answer, please try with the suggested code change. –  Sep 19 '22 at 16:07
  • Thanks for this! I am able to get it to work now. Can you please explain whats happening? And why a pointer to the array works but not the direct reference? – Ufder Sep 20 '22 at 00:21
0

As previous answer states, you channel is not read.

However, if you buffer your channel (buffer of 4 in your case) the code should finish.

Also removing the channel is viable solution. I am not sure why you pass the whole array you are building to the channel. I assume you examining how the array gets changed and how the routines work.

lsd
  • 504
  • 1
  • 4
  • 16
  • Hi, I tried without channels (that is preffered if possible), but the values do not persist in the array, same issue as https://stackoverflow.com/questions/54534588/get-responses-from-multiple-go-routines-into-an-array – Ufder Sep 19 '22 at 15:47
  • I understand that the goal is to learn here. I would start by dropping the procedures, the channel and the wait group. Try first single thread, that should work. Then start adding extra things. I haven't encountered such issue, but I would start simple. You might want to lock the array with mutex while the routines are modifying it. GL with go and have fun, good choice for a thing to learn. – lsd Sep 20 '22 at 07:28