我是Go的新手,正在寻找一种方法来处理使用100名工作人员的3000个查询并确保每个工作人员的连接(MySQL已经配置了超过100个连接)。这是我的尝试:
package main
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
var query *sql.Stmt
func worker(jobs <-chan int, results chan<- int) {
for _ = range jobs {
_, e := query.Exec("a")
if e != nil {
panic(e.Error())
}
results <- 1
}
}
func main() {
workers := 100
db, e := sql.Open("mysql", "foo:foo@/foo")
if e != nil {
panic(e.Error())
}
db.SetMaxOpenConns(workers)
db.SetMaxIdleConns(workers)
defer db.Close()
query, e = db.Prepare("INSERT INTO foo (foo) values(?)")
if e != nil {
panic(e.Error())
}
total := 30000
jobs := make(chan int, total)
results := make(chan int, total)
for w := 0; w < workers; w++ {
go worker(jobs, results)
}
for j := 0; j < total; j++ {
jobs <- j
}
close(jobs)
for r := 0; r < total; r++ {
<-results
}
}
它正在运作,但我不确定这是否是最佳方式。
如果您认为这是基于意见或根本不是一个好问题,请将其标记为已关闭,并留下评论解释原因。
答案 0 :(得分:1)
您从根本上有所作为,但要摆脱缓冲,您需要同时写信jobs
并阅读results
。否则,您的流程最终会被卡住 - 工作人员无法发送结果,因为没有人收到这些结果,并且您无法插入作业,因为工作人员已被阻止。
此处a boiled-down example on the Playground了解如何在后台推送作业的工作队列main
package main
import "fmt"
func worker(jobs <-chan int, results chan<- int) {
for _ = range jobs {
// ...do work here...
results <- 1
}
}
func main() {
workers := 10
total := 30
jobs := make(chan int)
results := make(chan int)
// start workers
for w := 0; w < workers; w++ {
go worker(jobs, results)
}
// insert jobs in background
go func() {
for j := 0; j < total; j++ {
jobs <- j
}
}()
// collect results
for i := 0; i < total; i++ {
<-results
fmt.Printf(".")
}
close(jobs)
}
要使特定代码生效,您必须知道您将获得多少结果。如果您不知道(例如,每项工作可能产生零个或多个结果),您可以使用sync.WaitGroup
到wait for the workers to finish, then close the result stream:
package main
import (
"fmt"
"sync"
)
func worker(jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
for _ = range jobs {
// ...do work here...
results <- 1
}
wg.Done()
}
func main() {
workers := 10
total := 30
jobs := make(chan int)
results := make(chan int)
wg := &sync.WaitGroup{}
// start workers
for w := 0; w < workers; w++ {
wg.Add(1)
go worker(jobs, results, wg)
}
// insert jobs in background
go func() {
for j := 0; j < total; j++ {
jobs <- j
}
close(jobs)
wg.Wait()
// all workers are done so no more results
close(results)
}()
// collect results
for _ = range results {
fmt.Printf(".")
}
}
还有许多其他更复杂的技巧可以在错误发生后阻止所有工作人员,将结果与原始工作放在同一顺序,或做其他类似的事情。听起来好像基本版本在这里工作。