Home > Mobile >  Goroutines - send critical data to the single goroutine and wait for result
Goroutines - send critical data to the single goroutine and wait for result

Time:07-19

I have many goroutines running in my application, and I have another goroutine that must handle only one request at the same period of time and then send the result back to caller.

It means other goroutines should wait until the necessary (single-operated) goroutine is busy.

[goroutine 1] <-
                 -
                   -
                     -
[goroutine 2]<- - - -  -> [Process some data in a single goroutine and send the result back to caller
                     -
                   -
                 -
[goroutine 3] <-

This is the diagram how it should look like

I'm very very new to Go and I have a poor knowledge how it should be correctly implemented.

Could someone provide me with some working example so I can run it on go playground?

CodePudding user response:

Here a code snippet which has a few worker-goroutines and one processor-goroutine. Only one single worker-goroutine can send something to the processor because the the processorChannel only allows one entry. When the processor is done, he sends back the response to the worker he got the work from.

package main

import (
    "fmt"
    "time"
)

type WorkPackage struct {
    value           int
    responseChannel chan int
}

func main() {
    processorChannel := make(chan *WorkPackage)

    for i := 0; i < 3; i   {
        go runWorker(processorChannel)
    }

    go runProcessor(processorChannel)

    // Do some clever waiting here like with wait groups
    time.Sleep(5 * time.Second)
}

func runWorker(processorChannel chan *WorkPackage) {
    responseChannel := make(chan int)

    for i := 0; i < 10; i   {
        processorChannel <- &WorkPackage{
            value:           i,
            responseChannel: responseChannel,
        }
        fmt.Printf("** Sent %d\n", i)

        response := <-responseChannel
        fmt.Printf("** Received the response %d\n", response)

        // Do some work
        time.Sleep(300 * time.Millisecond)
    }
}

func runProcessor(processorChannel chan *WorkPackage) {
    for workPackage := range processorChannel {
        fmt.Printf("## Received %d\n", workPackage.value)

        // Do some processing work
        time.Sleep(100 * time.Millisecond)
        
        workPackage.responseChannel <- workPackage.value * 100
    }
}

CodePudding user response:

I'll describe the approach with a goroutine that adds two numbers.

Declare request and response types for the goroutine. Include a channel of response values in the request:

type request struct {
    a, b  int          // add these two numbers
    ch chan response
}

type response struct {
    n int              // the result of adding the numbers
}

Kick off a goroutine that receives requests, executes the action and sends the response to the channel in the request:

func startAdder() chan request {
    ch := make(chan request)
    go func() {
        for req := range ch {
            req.ch <- response{req.a   req.b}
        }
    }()
    return ch
}

To add the numbers, send a request to the goroutine with a response channel. Receive on the response channel. Return the response value.

func add(ch chan request, a, b int) int {
    req := request{ch: make(chan response), a: a, b: b}
    ch <- req
    return (<-req.ch).n
}

Use it like this:

ch := startAdder()
fmt.Println(add(ch, 1, 2))

Run it on the GoLang PlayGround.

  • Related