1

To give you context,

The variable elementInput is dynamic. I do not know the exact length of it. It can be 10, 5, or etc.

The *Element channel type is struct

My example is working. But my problem is this implementation is still synchronized, because I am waiting for the channel return so that I can append it to my result

Can you pls help me how to concurrent call GetElements() function and preserve the order defined in elementInput (based on index)

elementInput := []string{FB_FRIENDS, BEAUTY_USERS, FITNESS_USERS, COMEDY_USERS}

wg.Add(len(elementInput))

for _, v := range elementInput {
    //create channel
    channel := make(chan *Element)
    //concurrent call
    go GetElements(ctx, page, channel)
    //Preserve the order

    var elementRes = *<-channel
    if len(elementRes.List) > 0 {
        el = append(el, elementRes)
    }

}

wg.Wait()
yssachan
  • 109
  • 7
  • Your implementation is not concurrent: on each loop iteration you create a channel, pass it to a function running on another goroutine and then receive from that channel—which blocks. So in fact you block waiting on the spawned goroutine to finish (provided its purpose is to do something and send the result over the submitted channel). – kostix Sep 23 '22 at 10:49
  • To make the code concurrent, you have to wait _after_ the loop is over (and the goroutines it spawned are either running or have completed or waiting to be run), and the preservation of order is then another question which has multiple solutions. The arguably simpler is: remember the "key" for each computation (those `FB_FRIENDS` etc). This can be done in mutiple ways: 1) have a slice where each channel is associated with this key; 2) pass the key to its goroutine and have it send it over with its result back. I'd go with the #2, and made each goroutine write to the same channel. – kostix Sep 23 '22 at 10:53
  • HI @kostix, I just started coding Go recently, and this is the frist time I am using channel. Can you please give a block of code with example of what you are suggesting? It is okay if it is not related to my example. I really appreciate it if ever. Thank you so much for your help. – yssachan Sep 23 '22 at 11:00

1 Answers1

4

Your implementation is not concurrent.

Reason after every subroutine call you are waiting for result, that is making this serial

Below is Sample implementation similar to your flow

  • calling Concurreny method which calls function concurrently
  • afterwards we loop and collect response from every above call
  • main subroutine sleep for 2 seconds

Go PlayGround with running code -> Sample Application

func main() {
    Concurrency()
    time.Sleep(2000)
}

func response(greeter string, channel chan *string) {
    reply := fmt.Sprintf("hello %s", greeter)
    channel <- &reply
}


func Concurrency() {
    events := []string{"ALICE", "BOB"}
    channels := make([]chan *string, 0)

    // start concurrently 
    for _, event := range events {
        channel := make(chan *string)
        go response(event, channel)
        channels = append(channels, channel)
    }

    // collect response
    response := make([]string, len(channels))

    for i := 0; i < len(channels); i++ {
        response[i] = *<-channels[i]
    }
   // print response 
    log.Printf("channel response %v", response)
}
recursion
  • 354
  • 6
  • 11