如何使用goroutine来执行for循环?

Pkz*_*zzz 1 go goroutine

假设我有一个像这样的切片:

stu = [{"id":"001","name":"A"} {"id":"002", "name":"B"}]也许还有更多这样的元素。切片内部是一个长字符串,我想使用 json.unmarshal 来解析它。

type Student struct {
   Id   string `json:"id"`
   Name string `json:"name"`
}

studentList := make([]Student,len(stu))
for i, st := range stu {
   go func(st string){
      studentList[i], err = getList(st)
      if err != nil {
         return ... //just example
      }
   }(st)
}
//and a function like this
func getList(stu string)(res Student, error){
   var student Student
   err := json.Unmarshal(([]byte)(stu), &student)
   if err != nil {
      return
   }
   return &student,nil
}
Run Code Online (Sandbox Code Playgroud)

我得到了 nil 结果,所以我想说 goroutine 是乱序执行的,所以我不知道它是否可以使用 StudentList[i] 来获取值。

Bri*_*its 6

以下是您的代码的一些潜在问题:

的值i可能不是您所期望的

for i, st := range stu {
   go func(st string){
      studentList[i], err = getList(st)
      if err != nil {
         return ... //just example
      }
   }(st)
}
Run Code Online (Sandbox Code Playgroud)

您启动了许多 goroutine,并在其中引用i. 问题是,i从启动 goroutine 的时间到 goroutine 引用它的时间(for 循环与它启动的 goroutine 同时运行)之间可能发生了变化。很可能在for任何 goroutine 之前完成,这意味着所有输出都将存储在最后一个元素中studentList(它们将相互覆盖,因此最终会得到一个值)。

一个简单的解决方案是传递i到 goroutine 函数(例如go func(st string, i int){}(st, i)(这会创建一个副本)。有关更多信息,请参阅此

学生列表的输出

你没有在问题中说,但我怀疑你在循环完成fmt.Println(studentList[1]后立即运行(或类似)for。如上所述,很可能此时没有任何 goroutine 完成(或者它们可能完成,你不知道)。使用 aWaitGroup是解决这个问题的一个相当简单的方法:

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()
Run Code Online (Sandbox Code Playgroud)

我已经在操场上纠正了这些问题。