如何实现查询功能

huangapple go评论75阅读模式
英文:

How to implement the query function

问题

我尝试开发一个程序,可以同时从多个复制的数据库中读取数据。它必须接受最先到达的响应。所以任务是实现query函数。我尝试使用select,但程序报错,我觉得我走错了方向。你能告诉我如何正确实现这个程序吗?

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 {
    // <- 这里是我实现的代码的开始部分
	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")
	}
    // -> 这里是代码的结束部分
}

func main() {
	conns := make([]Conn, 3)
	conns[0] = Conn1{}
	conns[1] = Conn2{}
	conns[2] = Conn3{}
	res := query(conns, "select * from users")
	fmt.Println(res)
}

你的代码中,使用了select语句来同时等待多个通道的结果。但是你定义的通道类型是chan Conn1chan Conn2chan Conn3,而不是chan Conn。因此,你需要将通道类型修改为chan Conn,并在调用DoQuery方法时传递正确的查询语句。

修改后的代码如下:

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 {
	ch1 := make(chan Conn)
	ch2 := make(chan Conn)
	ch3 := make(chan Conn)

	go func() {
		ch1 <- conns[0]
	}()
	go func() {
		ch2 <- conns[1]
	}()
	go func() {
		ch3 <- conns[2]
	}()

	select {
	case one := <-ch1:
		return one.DoQuery(query)
	case two := <-ch2:
		return two.DoQuery(query)
	case three := <-ch3:
		return three.DoQuery(query)
	}
}

func main() {
	conns := make([]Conn, 3)
	conns[0] = Conn1{}
	conns[1] = Conn2{}
	conns[2] = Conn3{}
	res := query(conns, "select * from users")
	fmt.Println(res)
}

这样修改后,程序会同时向三个通道发送请求,并等待最先到达的响应。然后返回该响应的结果。

英文:

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 (
&quot;fmt&quot;
&quot;time&quot;
)
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: &quot;Conn1&quot;}
}
func (c Conn2) DoQuery(query string) Result {
time.Sleep(2 * time.Second)
return Result{Query: query, ConnName: &quot;Conn2&quot;}
}
func (c Conn3) DoQuery(query string) Result {
time.Sleep(3 * time.Second)
return Result{Query: query, ConnName: &quot;Conn3&quot;}
}
func query(conns []Conn, query string) Result {
// &lt;- here is the beginning of code that I implemented
ch1 := make(chan Conn1)
ch2 := make(chan Conn2)
ch3 := make(chan Conn3)
select {
case one := &lt;-ch1:
return one.DoQuery(&quot;First query&quot;)
case two := &lt;-ch2:
return two.DoQuery(&quot;Second query&quot;)
case three := &lt;-ch3:
return three.DoQuery(&quot;Third query&quot;)
}
// -&gt; here is the end of code
}
func main() {
conns := make([]Conn, 3)
conns[0] = Conn1{}
conns[1] = Conn2{}
conns[2] = Conn3{}
res := query(conns, &quot;select * from users&quot;)
fmt.Println(res)
}

答案1

得分: 1

在每个goroutine中运行每个查询,并将每个查询的结果发送到一个单一的通道中。在主goroutine中接收通道以获取第一个结果。有关更多信息,请参见注释。

func query(conns []Conn, query string) Result {
    // 创建接收第一个结果的通道。容量len(conns)-1确保所有goroutine都可以向通道发送值并退出。
    ch := make(chan Result, len(conns)-1)

    // 在每个连接上启动一个goroutine进行查询。
    // https://go.dev/doc/faq#closures_and_goroutines 解释了为什么将conn作为参数传递。
    for _, conn := range conns {
        go func(conn Conn) {
            ch <- conn.DoQuery(query)
        }(conn)
    }

    // 等待第一个结果并返回它。
    return <-ch
}

在playground上运行示例

英文:

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 &lt;- conn.DoQuery(query)
}(conn)
}
// Wait for the the first result and return it.
return &lt;-ch
}

Run an example on the playground.

huangapple
  • 本文由 发表于 2022年7月30日 13:50:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/73173190.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定