在循环中调用的goroutine,使用指针的函数会覆盖数值吗?

huangapple go评论164阅读模式
英文:

Goroutine called in a loop on function with pointer overwrites value?

问题

我刚刚开始学习Go语言,并遇到了指针在这种语言中如何处理的问题。

我有以下代码,但无法弄清楚如何修复它以获得正确的响应。

func (me *Str) Start()更改为func (me Str) Start()可以解决问题,但我需要将其作为引用来编写此结构(其中将包含通道)。

示例代码(https://play.golang.org/p/EsPejyCrX7):

package main

import (
    "fmt"
    "sync"
)

var wg1 sync.WaitGroup

type Str struct {
    id int
}

func (me *Str) Start() {
    wg1.Add(1)
    fmt.Println("F1 ", me)
    go me.startFn()
}

func (me *Str) startFn() {
    defer wg1.Done()
    fmt.Println("F2 ", me)
}

func main() {
    Fl2 := []Str{
        {1},
        {2},
        {3},
    }

    for _, fl := range Fl2 {
        fl.Start()
    }
    wg1.Wait()
}

响应:

F1  &{1}
F1  &{2}
F1  &{3}
F2  &{3}
F2  &{3}
F2  &{3}

预期响应(F2 可能是随机的):

F1  &{1}
F1  &{2}
F1  &{3}
F2  &{3}
F2  &{2}
F2  &{1}
英文:

I have just started playing with Go and stumbled upon problem how the pointers are handled in this language.

I have such code and can`t figure out how to fix it to get the correct response.

Changing func (me *Str) Start() to func (me Str) Start() fixes the problem, but I need this as reference to write this structure (it will have channel in it).

Sample code (https://play.golang.org/p/EsPejyCrX7):

package main

import (
	"fmt"
	"sync"
)

var wg1 sync.WaitGroup

type Str struct {
	id int
}

func (me *Str) Start() {
	wg1.Add(1)
	fmt.Println("F1 ", me)
	go me.startFn()
}

func (me *Str) startFn() {
	defer wg1.Done()
	fmt.Println("F2 ", me)
}

func main() {
	Fl2 := []Str{
		{1},
		{2},
		{3},
	}

	for _, fl := range Fl2 {
		fl.Start()
	}
	wg1.Wait()
}

Response:

F1  &{1}
F1  &{2}
F1  &{3}
F2  &{3}
F2  &{3}
F2  &{3}

Expected response (F2 can be random):

F1  &{1}
F1  &{2}
F1  &{3}
F2  &{3}
F2  &{2}
F2  &{1}

答案1

得分: 2

在循环迭代变量上使用goroutines是一个常见的错误。

通过范围索引调用Fl2元素的.Start方法,而不是范围值(playground):

for i := range Fl2 {
    Fl2[i].Start()
}

然而,由于goroutines的调度,输出可能仍然不会完全符合您的期望,例如可能会像这样:

F1  &{1}
F1  &{2}
F1  &{3}
F2  &{3}
F2  &{1}
F2  &{2}
英文:

Using goroutines on loop iterator variables is a common mistake.

Call .Start on the element of Fl2 by the range index, instead of the range value (playground):

for i := range Fl2 {
	Fl2[i].Start()
}

However, the output might still not become exactly as you expect,
due to the scheduling of the goroutines,
for example it might be like this:

F1  &{1}
F1  &{2}
F1  &{3}
F2  &{3}
F2  &{1}
F2  &{2}

huangapple
  • 本文由 发表于 2017年7月2日 05:47:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/44865693.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定