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))