golang range for循环中如何正确的给goroutine传参
1.code example
公共方法
func testDomain(ii string) { time.Sleep(time.Second * 4) fmt.Printf("pid: %d___point addr: %d___%s \n", GoID(), &ii, ii) }
func GoID() int { var buf [64]byte n := runtime.Stack(buf[:], false) idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0] id, err := strconv.Atoi(idField) if err != nil { panic(fmt.Sprintf("cannot get goroutine id: %v", err)) } return id }
2. 错误示范
var a []string
for i := 1; i < 5; i++ {
a = append(a, fmt.Sprintf("%d", i))
}
for _, i := range a { fmt.Printf("-----%s---\n", i) go func() { time.Sleep(time.Second * 4) testDomain(i) }() }
打印发现i每次地址都是同一个
协助每次先阻塞4秒
4秒后 i的值是4, 这是协程中的方法testDomain开始工作,将i的值传给自己的形参
3. 正确示范
for _, i := range a { fmt.Printf("-----%s---\n", i) go func(a string) { //time.Sleep(time.Second * 4) testDomain(a) }(i) }
这种操作会先将i的值传递给形参a,i的变化不会对testDomain方法的执行产生影响
4. 完整代码
package main import ( "fmt" "runtime" "strconv" "strings" "time" ) func main() { var a []string for i := 1; i < 5; i++ { a = append(a, fmt.Sprintf("%d", i)) } for _, i := range a { fmt.Printf("-----%s---\n", i) go func(a string) { //time.Sleep(time.Second * 4) testDomain(a) }(i) go func() { time.Sleep(time.Second * 4) testDomain(i) }() fmt.Println(&i) time.Sleep(time.Second * 1) } time.Sleep(100 * time.Second) } func testDomain(ii string) { time.Sleep(time.Second * 4) fmt.Printf("pid: %d___point addr: %d___%s \n", GoID(), &ii, ii) } func GoID() int { var buf [64]byte n := runtime.Stack(buf[:], false) idField := strings.Fields(strings.TrimPrefix(string(buf[:n]), "goroutine "))[0] id, err := strconv.Atoi(idField) if err != nil { panic(fmt.Sprintf("cannot get goroutine id: %v", err)) } return id }
没有什么是写一万遍还不会的,如果有那就再写一万遍。