2 回答
TA贡献1895条经验 获得超7个赞
以下是代码中的一些潜在问题:
i的值可能不是你所期望的
for i, st := range stu {
go func(st string){
studentList[i], err = getList(st)
if err != nil {
return ... //just example
}
}(st)
}
你启动了一些goroutines,并在其中引用了。问题是,在你启动 goroutine 的时间和 goroutine 引用它的时间之间,它可能已经发生了变化(for 循环同时运行到它启动的 goroutines)。很可能在任何 goroutines 之前的完成意味着所有输出都将存储在 的最后一个元素中(它们将相互覆盖,因此您最终会得到一个值)。iiforstudentList
一个简单的解决方案是传递到 goroutine 函数(例如 (这将创建一个副本)。有关详细信息,请参阅此内容。igo func(st string, i int){}(st, i)
学生列表的输出
你没有在问题中说,但我怀疑你在循环完成后立即运行(或类似)。如上所述,很可能在这一点上没有一个goroutines完成(或者他们可能,你不知道)。使用 a 是一种相当简单的方法:fmt.Println(studentList[1]forWaitGroup
var wg sync.WaitGroup
wg.Add(len(stu))
for i, st := range stu {
go func(st string, i int) {
var err error
studentList[i], err = getList(st)
if err != nil {
panic(err)
}
wg.Done()
}(st, i)
}
wg.Wait()
我已经在操场上纠正了这些问题。
TA贡献1801条经验 获得超8个赞
不是因为这个
goroutine执行的顺序不正常
这里至少有两个问题:
您不应该在 goroutine 中使用 for 循环变量。i
多个 goroutines 读取 ,对于循环修改,这里是争用条件。要按预期工作,请将代码更改为:iii
for i, st := range stu {
go func(i int, st string){
studentList[i], err = getList(st)
if err != nil {
return ... //just example
}
}(i, st)
}
更重要的是,用来等待所有的goroutine。sync.WaitGroup
var wg sync.WaitGroup
for i, st := range stu {
wg.Add(1)
go func(i int, st string){
defer wg.Done()
studentList[i], err = getList(st)
if err != nil {
return ... //just example
}
}(i, st)
}
wg.Wait()
P.S.:(警告:也许并不总是这样)
这条线,虽然它可能不会引起数据竞争,但它对CPU缓存线并不友好。最好避免编写这样的代码。studentList[i], err = getList(st)
- 2 回答
- 0 关注
- 163 浏览
添加回答
举报