You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 14:15:07