I try to develop a program that reads from multiple replicated databases simultaneously. It must accept the response that arrives first. So the tsk is to implement the query
function. I tried select
, but the program gives an error and I think I'm going in the wrong direction. Can you tell me how to properly implement this program.
package main
import (
"fmt"
"time"
)
type Conn interface {
DoQuery(query string) Result
}
type Result struct {
Query string
ConnName string
}
type Conn1 struct{}
type Conn2 struct{}
type Conn3 struct{}
func (c Conn1) DoQuery(query string) Result {
time.Sleep(1 * time.Second)
return Result{Query: query, ConnName: "Conn1"}
}
func (c Conn2) DoQuery(query string) Result {
time.Sleep(2 * time.Second)
return Result{Query: query, ConnName: "Conn2"}
}
func (c Conn3) DoQuery(query string) Result {
time.Sleep(3 * time.Second)
return Result{Query: query, ConnName: "Conn3"}
}
func query(conns []Conn, query string) Result {
// <- here is the beginning of code that I implemented
ch1 := make(chan Conn1)
ch2 := make(chan Conn2)
ch3 := make(chan Conn3)
select {
case one := <-ch1:
return one.DoQuery("First query")
case two := <-ch2:
return two.DoQuery("Second query")
case three := <-ch3:
return three.DoQuery("Third query")
}
// -> here is the end of code
}
func main() {
conns := make([]Conn, 3)
conns[0] = Conn1{}
conns[1] = Conn2{}
conns[2] = Conn3{}
res := query(conns, "select * from users")
fmt.Println(res)
}
CodePudding user response:
Run each query in a goroutine and send the result of each query to a single channel. Receive on the channel in the main goroutine to get the first result. See the commentary for more info.
func query(conns []Conn, query string) Result {
// Create the channel to receive the first result. The capacity
// len(conns)-1 ensures that all goroutines can send a value to the
// channel and exit.
ch := make(chan Result, len(conns)-1)
// Start a goroutine to query on each connection.
// https://go.dev/doc/faq#closures_and_goroutines explains
// why conn is passed as an argument.
for _, conn := range conns {
go func(conn Conn) {
ch <- conn.DoQuery(query)
}(conn)
}
// Wait for the the first result and return it.
return <-ch
}