Go协程传入不同查询字符串仍出现重复结果问题求助
Go多协程Ping结果重复问题修复方案
核心问题点
- 全局变量并发冲突:你定义的
id、ip、rttr是全局变量,两个并发执行的doPing协程会同时修改这些变量,无同步机制会导致值被互相覆盖,输出结果混乱重复。 - 闭包捕获循环变量异常:
OnRecv回调是闭包,直接捕获了for循环复用的id、ip变量,回调触发时循环已经进入下一轮迭代,拿到的不是当前IP对应的值,导致结果匹配错误。 - 重复初始化数据库连接:每次
doPing执行都调用sql.Open新建连接池,浪费资源也增加异常概率,sql.DB本身是并发安全的连接池,全局初始化一次即可。 - 错误处理不合理:IP解析失败直接调用
os.Exit(1)会终止整个程序,建议跳过错误IP继续执行。
修复后代码示例
package main import ( "database/sql" "fmt" _ "github.com/go-sql-driver/mysql" "github.com/tatsushid/go-fastping" "log" "net" "sync" "time" ) var db *sql.DB var wg sync.WaitGroup // 全局初始化一次数据库连接 func initDB() { var err error db, err = sql.Open("mysql", "你的数据库连接信息") if err != nil { panic(err) } db.SetConnMaxLifetime(time.Minute * 15) db.SetMaxOpenConns(10) db.SetMaxIdleConns(10) // 连通性校验 if err = db.Ping(); err != nil { panic(err) } } func main() { initDB() defer db.Close() for { queries := []string{ "SELECT id, ip FROM hosts where id < 50", "SELECT id, ip FROM hosts where id >= 50", } for _, query := range queries { wg.Add(1) go doPing(query) } wg.Wait() } } func doPing(query string) { defer wg.Done() fmt.Println("Worker started!") rows, err := db.Query(query) fmt.Println("QUERY:") fmt.Println(query) fmt.Println("--------") if err != nil { log.Println("查询失败:", err) return } defer rows.Close() for rows.Next() { // 变量定义在循环内部,每次迭代都是独立的新变量 var id int var ip string var rttr time.Duration err := rows.Scan(&id, &ip) if err != nil { log.Println("行扫描失败:", err) continue } p := fastping.NewPinger() ra, err := net.ResolveIPAddr("ip4:icmp", ip) if err != nil { log.Println("IP解析失败:", ip, err) continue } p.AddIPAddr(ra) // 存储当前迭代的值,避免闭包捕获循环复用变量 currentID := id p.OnRecv = func(addr *net.IPAddr, rtt time.Duration) { fmt.Printf("IP Addr: %s receive, RTT: %v\n", addr.String(), rtt) fmt.Println("对应ID:", currentID) rttr = rtt } p.OnIdle = func() { // 原有数据库逻辑直接使用当前循环内的currentID、rttr即可 } err = p.Run() if err != nil { log.Println("Ping执行失败:", ip, err) } time.Sleep(time.Second) } }
内容的提问来源于stack exchange,提问作者Christiaan
相关产品推荐
相关产品推荐

