简体   繁体   English

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

[英]Go routine returns less results then the actual result

I have a LOOP that does the hashing inside for a given key and returns the result, but on Result, If I have 1500 list of URL that goes inside LOOP, it never returns the result of 1500, it returns always lesser then 1500.我有一个 LOOP,它对给定的键在内部进行散列并返回结果,但在结果上,如果我有 1500 个 URL 列表进入 LOOP,它永远不会返回 1500 的结果,它总是返回小于 1500。

What am I doing wrong in below:我在下面做错了什么:

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
}

I tried both method for Add - one inside loop by 1 and one outside loop by total length.我尝试了两种Add方法 - 一个内部循环为 1,一个外部循环为总长度。

I want function to return all 1500 URL list and not just "700, 977, 1123" random list.我希望函数返回所有 1500 个 URL 列表,而不仅仅是“700、977、1123”随机列表。

It looks like - wg.Wait() is not waiting for all the wg.Add - added看起来 - wg.Wait()没有等待所有wg.Add - 添加

There are a couple of errors in this program:这个程序有几个错误:

  1. You are using the loop variable inside the goroutine.您正在 goroutine 中使用循环变量。 The loop variable is rewritten at each iteration, so when the goroutine uses the url , it might have already moved on to the next URL, thus you end up with multiple goroutines hashing the same URL.循环变量在每次迭代时都被重写,所以当 goroutine 使用url ,它可能已经移动到下一个 URL,因此你最终会得到多个 goroutine 散列相同的 URL。 To fix:修理:
    for _, url := range URLLists {
        url:=url // Create a copy of the url
        // wg.Add(1)  OR above for loop
  1. You have a race condition.你有一个竞争条件。 You have to protect access to response.URL because it is being written by multiple goroutines.您必须保护对response.URL访问,因为它是由多个 goroutine 编写的。 You can use a mutex:您可以使用互斥锁:
lock:=sync.Mutex{}
for _,url:=...
  ...
  lock.Lock()
  response.URL = append(response.URL, list)
  lock.Unlock()

A better way would be to send these over a channel.更好的方法是通过通道发送这些。

You have a pretty serious race condition here:你在这里有一个非常严重的比赛状况:

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

If you're starting as many as 1500 concurrent Go routines, you will have many hundreds of them all attempting to execute this line at once.如果您要启动多达 1500 个并发 Go 例程,您将有数百个例程都试图同时执行这一行。 They will be constantly overwriting changes to the array.它们将不断覆盖对数组的更改。

You need to protect the insertion of new data into this slice with a sync.Mutex , or be sending results over a channel and having a single Go routine reading from that channel and appending to the list.您需要使用sync.Mutex保护将新数据插入此切片,或者通过通道发送结果并让单个 Go 例程从该通道读取并附加到列表中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM