如何实现查询功能

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

How to implement the query function

问题

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

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. type Conn interface {
  7. DoQuery(query string) Result
  8. }
  9. type Result struct {
  10. Query string
  11. ConnName string
  12. }
  13. type Conn1 struct{}
  14. type Conn2 struct{}
  15. type Conn3 struct{}
  16. func (c Conn1) DoQuery(query string) Result {
  17. time.Sleep(1 * time.Second)
  18. return Result{Query: query, ConnName: "Conn1"}
  19. }
  20. func (c Conn2) DoQuery(query string) Result {
  21. time.Sleep(2 * time.Second)
  22. return Result{Query: query, ConnName: "Conn2"}
  23. }
  24. func (c Conn3) DoQuery(query string) Result {
  25. time.Sleep(3 * time.Second)
  26. return Result{Query: query, ConnName: "Conn3"}
  27. }
  28. func query(conns []Conn, query string) Result {
  29. // <- 这里是我实现的代码的开始部分
  30. ch1 := make(chan Conn1)
  31. ch2 := make(chan Conn2)
  32. ch3 := make(chan Conn3)
  33. select {
  34. case one := <-ch1:
  35. return one.DoQuery("First query")
  36. case two := <-ch2:
  37. return two.DoQuery("Second query")
  38. case three := <-ch3:
  39. return three.DoQuery("Third query")
  40. }
  41. // -> 这里是代码的结束部分
  42. }
  43. func main() {
  44. conns := make([]Conn, 3)
  45. conns[0] = Conn1{}
  46. conns[1] = Conn2{}
  47. conns[2] = Conn3{}
  48. res := query(conns, "select * from users")
  49. fmt.Println(res)
  50. }

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

修改后的代码如下:

  1. package main
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. type Conn interface {
  7. DoQuery(query string) Result
  8. }
  9. type Result struct {
  10. Query string
  11. ConnName string
  12. }
  13. type Conn1 struct{}
  14. type Conn2 struct{}
  15. type Conn3 struct{}
  16. func (c Conn1) DoQuery(query string) Result {
  17. time.Sleep(1 * time.Second)
  18. return Result{Query: query, ConnName: "Conn1"}
  19. }
  20. func (c Conn2) DoQuery(query string) Result {
  21. time.Sleep(2 * time.Second)
  22. return Result{Query: query, ConnName: "Conn2"}
  23. }
  24. func (c Conn3) DoQuery(query string) Result {
  25. time.Sleep(3 * time.Second)
  26. return Result{Query: query, ConnName: "Conn3"}
  27. }
  28. func query(conns []Conn, query string) Result {
  29. ch1 := make(chan Conn)
  30. ch2 := make(chan Conn)
  31. ch3 := make(chan Conn)
  32. go func() {
  33. ch1 <- conns[0]
  34. }()
  35. go func() {
  36. ch2 <- conns[1]
  37. }()
  38. go func() {
  39. ch3 <- conns[2]
  40. }()
  41. select {
  42. case one := <-ch1:
  43. return one.DoQuery(query)
  44. case two := <-ch2:
  45. return two.DoQuery(query)
  46. case three := <-ch3:
  47. return three.DoQuery(query)
  48. }
  49. }
  50. func main() {
  51. conns := make([]Conn, 3)
  52. conns[0] = Conn1{}
  53. conns[1] = Conn2{}
  54. conns[2] = Conn3{}
  55. res := query(conns, "select * from users")
  56. fmt.Println(res)
  57. }

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

英文:

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.

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;time&quot;
  5. )
  6. type Conn interface {
  7. DoQuery(query string) Result
  8. }
  9. type Result struct {
  10. Query string
  11. ConnName string
  12. }
  13. type Conn1 struct{}
  14. type Conn2 struct{}
  15. type Conn3 struct{}
  16. func (c Conn1) DoQuery(query string) Result {
  17. time.Sleep(1 * time.Second)
  18. return Result{Query: query, ConnName: &quot;Conn1&quot;}
  19. }
  20. func (c Conn2) DoQuery(query string) Result {
  21. time.Sleep(2 * time.Second)
  22. return Result{Query: query, ConnName: &quot;Conn2&quot;}
  23. }
  24. func (c Conn3) DoQuery(query string) Result {
  25. time.Sleep(3 * time.Second)
  26. return Result{Query: query, ConnName: &quot;Conn3&quot;}
  27. }
  28. func query(conns []Conn, query string) Result {
  29. // &lt;- here is the beginning of code that I implemented
  30. ch1 := make(chan Conn1)
  31. ch2 := make(chan Conn2)
  32. ch3 := make(chan Conn3)
  33. select {
  34. case one := &lt;-ch1:
  35. return one.DoQuery(&quot;First query&quot;)
  36. case two := &lt;-ch2:
  37. return two.DoQuery(&quot;Second query&quot;)
  38. case three := &lt;-ch3:
  39. return three.DoQuery(&quot;Third query&quot;)
  40. }
  41. // -&gt; here is the end of code
  42. }
  43. func main() {
  44. conns := make([]Conn, 3)
  45. conns[0] = Conn1{}
  46. conns[1] = Conn2{}
  47. conns[2] = Conn3{}
  48. res := query(conns, &quot;select * from users&quot;)
  49. fmt.Println(res)
  50. }

答案1

得分: 1

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

  1. func query(conns []Conn, query string) Result {
  2. // 创建接收第一个结果的通道。容量len(conns)-1确保所有goroutine都可以向通道发送值并退出。
  3. ch := make(chan Result, len(conns)-1)
  4. // 在每个连接上启动一个goroutine进行查询。
  5. // https://go.dev/doc/faq#closures_and_goroutines 解释了为什么将conn作为参数传递。
  6. for _, conn := range conns {
  7. go func(conn Conn) {
  8. ch <- conn.DoQuery(query)
  9. }(conn)
  10. }
  11. // 等待第一个结果并返回它。
  12. return <-ch
  13. }

在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.

  1. func query(conns []Conn, query string) Result {
  2. // Create the channel to receive the first result. The capacity
  3. // len(conns)-1 ensures that all goroutines can send a value to the
  4. // channel and exit.
  5. ch := make(chan Result, len(conns)-1)
  6. // Start a goroutine to query on each connection.
  7. // https://go.dev/doc/faq#closures_and_goroutines explains
  8. // why conn is passed as an argument.
  9. for _, conn := range conns {
  10. go func(conn Conn) {
  11. ch &lt;- conn.DoQuery(query)
  12. }(conn)
  13. }
  14. // Wait for the the first result and return it.
  15. return &lt;-ch
  16. }

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:

确定