我在循环中有一个 goroutine,我想同时为 ms.Entries 中的每个项目执行一个 goroutine,但它只针对循环中的最后一个项目运行。
我从一个更大的程序中抽象出了我的示例...... https://play.golang.org/p/whUMQ3pjq81
package main
import (
"fmt"
"sync"
)
type MyStruct struct {
Entry *Entry
Entries *[]Entry
}
type Entry struct {
ID int
Name string
}
type Fn struct {
Res string
Err error
}
func main() {
e1 := Entry{ID: 1, Name: "First"}
e2 := Entry{ID: 2, Name: "Second"}
ms := &MyStruct{
Entries: &[]Entry{e1, e2},
}
fmt.Printf("MS: %+v\n", ms)
var wg sync.WaitGroup
fnChan := make(chan *Fn)
go func() {
wg.Wait()
close(fnChan)
}()
var fns []func() (string, error)
fns = append(fns, ms.actionA)
fns = append(fns, ms.actionB)
for i, entry := range *ms.Entries {
fmt.Printf("%d: %+v\n", i, entry)
ms.Entry = &entry
for j, fn := range fns {
fmt.Printf("fn loop %d\n", j)
wg.Add(1)
go ms.process(&wg, fn, fnChan)
}
}
for d := range fnChan {
fmt.Printf("fnchan: %+v\n", d)
}
}
func (m *MyStruct) actionA() (string, error) {
fmt.Println("actionA")
fmt.Printf("Entry: %s\n", m.Entry.Name)
return "actionA done", nil
}
func (m *MyStruct) actionB() (string, error) {
fmt.Println("actionB")
fmt.Printf("Entry: %s\n", m.Entry.Name)
return "actionB done", nil
}
func (m *MyStruct) process(wg *sync.WaitGroup, fn func() (string, error), fnChan chan<- *Fn) {
fmt.Println("processing")
var err error
defer wg.Done()
res, err := fn()
if err != nil {
fnChan <- &Fn{Err: err}
return
}
fnChan <- &Fn{Res: res}
}
Run Code Online (Sandbox Code Playgroud)
问题
你这里有一个问题:
ms.Entry = &entry
Run Code Online (Sandbox Code Playgroud)
当你使用循环时,像这样:
for i, entry := range *ms.Entries {
Run Code Online (Sandbox Code Playgroud)
变量“entry”仅声明一次。
因此&entry将有一个常数值(每次迭代中的值相同)。
但即使您解决了这个问题,另一个问题是您ms在每次迭代中都使用相同的对象。
因此,当您启动不同的 goroutine 时,ms.Entry = ...您在第二次迭代中执行的语句将修改共享ms对象。
您还fn按照其他答案中的描述在迭代之间“共享”变量,因此您还应该捕获该变量。
使固定
我建议您Entry从结构中删除该字段(您不需要它,因为您已经拥有完整的数组),并使用数组位置来引用当前条目。
您应该i int向“action”和“process”函数添加一个参数。
您还需要“捕获”fn变量。
for i, entry := range *ms.Entries {
...
for j, fn := range fns {
...
fn := fn // capture the fn variable
go ms.process(&wg, fn, fnChan, i) // sending index here
}
}
Run Code Online (Sandbox Code Playgroud)
请参阅此处修改后的游乐场:
https://play.golang.org/p/uuw7r4kGBPb
| 归档时间: |
|
| 查看次数: |
2692 次 |
| 最近记录: |