工作池来处理查询

时间:2014-10-30 15:27:00

标签: mysql go

我是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
    }
}

它正在运作,但我不确定这是否是最佳方式。

如果您认为这是基于意见或根本不是一个好问题,请将其标记为已关闭,并留下评论解释原因。

1 个答案:

答案 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.WaitGroupwait 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(".")
    }

}

还有许多其他更复杂的技巧可以在错误发生后阻止所有工作人员,将结果与原始工作放在同一顺序,或做其他类似的事情。听起来好像基本版本在这里工作。