Go routine returns 结果比实际结果少
Go routine returns less results then the actual result
我有一个 LOOP,它在内部对给定的键进行哈希处理,然后 return 得到结果,但是在结果上,如果我有 1500 个 URL 的列表进入 LOOP,它永远不会return 是 1500 的结果,它 return 总是小于 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 和一个外部循环总长度。
我想要 return 所有 1500 URL 列表的功能,而不仅仅是“700、977、1123”随机列表。
看起来 - wg.Wait()
不是等待所有 wg.Add
- 添加
你的竞争条件很严重:
response.URL = append(response.URL, list)
如果您启动多达 1500 个并发 Go 例程,您将有数百个例程同时尝试执行此行。他们将不断地覆盖对数组的更改。
您需要使用 sync.Mutex
来保护将新数据插入到此切片中,或者通过通道发送结果并让单个 Go 例程从该通道读取并附加到列表中。
这个程序有几个错误:
- 您正在 goroutine 中使用循环变量。循环变量在每次迭代时都会被重写,所以当 goroutine 使用
url
时,它可能已经移动到下一个 URL,因此你最终会得到多个 goroutines 散列相同的 URL ].修复:
for _, url := range URLLists {
url:=url // Create a copy of the url
// wg.Add(1) OR above for loop
- 你有竞争条件。你必须保护对
response.URL
的访问,因为它是由多个 goroutines 编写的。您可以使用互斥体:
lock:=sync.Mutex{}
for _,url:=...
...
lock.Lock()
response.URL = append(response.URL, list)
lock.Unlock()
更好的方法是通过频道发送这些内容。
我有一个 LOOP,它在内部对给定的键进行哈希处理,然后 return 得到结果,但是在结果上,如果我有 1500 个 URL 的列表进入 LOOP,它永远不会return 是 1500 的结果,它 return 总是小于 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 和一个外部循环总长度。
我想要 return 所有 1500 URL 列表的功能,而不仅仅是“700、977、1123”随机列表。
看起来 - wg.Wait()
不是等待所有 wg.Add
- 添加
你的竞争条件很严重:
response.URL = append(response.URL, list)
如果您启动多达 1500 个并发 Go 例程,您将有数百个例程同时尝试执行此行。他们将不断地覆盖对数组的更改。
您需要使用 sync.Mutex
来保护将新数据插入到此切片中,或者通过通道发送结果并让单个 Go 例程从该通道读取并附加到列表中。
这个程序有几个错误:
- 您正在 goroutine 中使用循环变量。循环变量在每次迭代时都会被重写,所以当 goroutine 使用
url
时,它可能已经移动到下一个 URL,因此你最终会得到多个 goroutines 散列相同的 URL ].修复:
for _, url := range URLLists {
url:=url // Create a copy of the url
// wg.Add(1) OR above for loop
- 你有竞争条件。你必须保护对
response.URL
的访问,因为它是由多个 goroutines 编写的。您可以使用互斥体:
lock:=sync.Mutex{}
for _,url:=...
...
lock.Lock()
response.URL = append(response.URL, list)
lock.Unlock()
更好的方法是通过频道发送这些内容。