为了账号安全,请及时绑定邮箱和手机立即绑定

Go 例程返回的结果少于实际结果

Go 例程返回的结果少于实际结果

Go
jeck猫 2022-10-10 17:01:19
我有一个循环,它对给定的键进行哈希处理并返回结果,但是在结果上,如果我有 1500 个进入循环的 URL 列表,它永远不会返回 1500 的结果,它总是返回小于 1500。我在下面做错了什么: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 {        // wg.Add(1)  OR above for loop        go func() {            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()        }()    }    wg.Wait()    jR, err := json.Marshal(response)    if err != nil {        w.Write([]byte(`{"success": false, "url" : ""}`))    } else {        w.Write(jR)    }    return}我尝试了这两种方法Add- 一个内部循环乘以 1,一个外部循环乘以总长度。我希望函数返回所有 1500 个 URL 列表,而不仅仅是“700、977、1123”随机列表。看起来 -wg.Wait()不是在等待所有wg.Add- 添加
查看完整描述

2 回答

?
哆啦的时光机

TA贡献1779条经验 获得超6个赞

这个程序有几个错误:


您正在 goroutine 中使用循环变量。循环变量在每次迭代时都会被重写,因此当 goroutine 使用 时url,它可能已经移动到下一个 URL,因此您最终会得到多个 goroutine 散列相同的 URL。修理:

    for _, url := range URLLists {

        url:=url // Create a copy of the url

        // wg.Add(1)  OR above for loop

你有一个竞争条件。你必须保护对它的访问,response.URL因为它是由多个 goroutine 编写的。您可以使用互斥锁:

lock:=sync.Mutex{}

for _,url:=...

  ...

  lock.Lock()

  response.URL = append(response.URL, list)

  lock.Unlock()

更好的方法是通过通道发送这些。


查看完整回答
反对 回复 2022-10-10
?
子衿沉夜

TA贡献1828条经验 获得超3个赞

你在这里有一个非常严重的比赛条件:

response.URL = append(response.URL, list)

如果您要启动多达 1500 个并发 Go 例程,那么您将有数百个都尝试同时执行这一行。他们将不断地覆盖对数组的更改。

您需要使用 保护将新数据插入到此切片中sync.Mutex,或者通过通道发送结果并让单个 Go 例程从该通道读取并附加到列表中。


查看完整回答
反对 回复 2022-10-10
  • 2 回答
  • 0 关注
  • 114 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信