Go goroutine处理URL返回结果数少于实际输入量该如何解决
问题根因
你的代码触发了Go语言经典的循环变量捕获陷阱:
- for range遍历过程中,循环变量
url是整个迭代周期内复用的临时变量,内存地址固定,每次遍历只会更新该地址存储的URL值 - 你启动goroutine时,匿名函数没有将
url作为入参传入,而是直接捕获了外部url变量的引用,等到goroutine实际执行时,循环大概率已经迭代到了后面的环节,拿到的url不是启动goroutine时对应的那条URL - 这会导致大量goroutine重复处理同一条URL、甚至拿到异常的
url值导致encoding.HexEncodeURL执行失败提前退出,最终结果条数随机少于输入条数。
修复方案
只需要修改goroutine匿名函数的定义,将当前迭代的url作为参数传入即可,启动goroutine时会自动拷贝当前url的值到函数内部,每个goroutine都会拿到独立的URL值:
if len(URLLists) > 0 { var base = "https://example.com/query?=" var wg sync.WaitGroup var mutex = sync.Mutex{} wg.Add(len(URLLists)) for _, url := range URLLists { // 将url作为参数传入匿名函数 go func(url string) { defer wg.Done() hmac := "HMAX_123" out := encoding.HexEncodeURL(hmac, url) final := base + out list := Lists{ Old: url, New: final, } mutex.Lock() response.URL = append(response.URL, list) mutex.Unlock() }(url) // 这里传入当前迭代的url值 } wg.Wait() jR, err := json.Marshal(response) if err != nil { w.Write([]byte(`{"success": false, "url" : ""}`)) } else { w.Write(jR) } return }
补充说明
你当前使用的wg.Add在循环外一次性添加全量计数、以及用mutex保护切片append的写法都是正确的,不需要调整,问题和WaitGroup的逻辑无关。
内容的提问来源于stack exchange,提问作者Rockabee
相关产品推荐
相关产品推荐

