如何使用 goroutine 执行 for 循环?

假设我有一个切片,如:


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

}

我得到了nil结果,所以我会说goroutine执行的顺序是无序的,所以我不知道它是否可以使用studentList[i]来获得价值。


不负相思意
浏览 164回答 2
2回答

人到中年有点甜

以下是代码中的一些潜在问题: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]forWaitGroupvar wg sync.WaitGroupwg.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()我已经在操场上纠正了这些问题。

蝴蝶刀刀

不是因为这个goroutine执行的顺序不正常这里至少有两个问题:您不应该在 goroutine 中使用 for 循环变量。i多个 goroutines 读取 ,对于循环修改,这里是争用条件。要按预期工作,请将代码更改为:iiifor 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.WaitGroupvar wg sync.WaitGroupfor 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)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go