go 并发编程

滴滴滴--你不是爱拖延,而是爱逃避 / 2024-09-23 / 原文

//python java php 多线程编程,多用户编程,多线程和多进程存在的问题主要是耗费内存。

//内存 线程切换 web2.0 用户级线程 绿城 轻量级线程 协程 

// 内存占用小(2k)、切换快,go 语言的协程, go语言诞生之后只有协程可用 goroutine  非常方便

package main

import (
"fmt"
"time"
)

func asyncPrint() {
fmt.Println("bobby")

}

func main() {
go asyncPrint()
fmt.Println("main")
time.Sleep(time.Second)

}

 匿名函数启动go routine

func main() {
    // 匿名函数启动go routine
    go func() {
        for {
            fmt.Println("bobby")
            time.Sleep(time.Second)
        }

    }()

    fmt.Println("main")
    time.Sleep(10 * time.Second)

}

 for 循环和闭包

func main() {
    // 匿名函数启动go routine
    // 1、闭包 2、 for 循环的问题。 for 循环的时候每次这个变量会被重用。
    // 由于每次for循环的时候,i变量会被重用,当我进行到第二轮的时候这个i就变了
  // 主要原因是goroutine 是并行的执行的和for循环执行是异步的取的数字 可能重复
for i := 0; i < 100; i++ { fmt.Println("这里是", i) go func() { fmt.Println(i) }() } fmt.Println("main") time.Sleep(10 * time.Second) }
这里是 0
这里是 1
这里是 2
这里是 3
这里是 4
这里是 5
这里是 6
这里是 7
这里是 8
这里是 9
这里是 10
这里是 11
这里是 12
这里是 13
这里是 14
这里是 15
这里是 16
这里是 17
这里是 18
这里是 19
这里是 20
这里是 21
这里是 22
这里是 23
这里是 24
这里是 25
这里是 26
这里是 27
这里是 28
这里是 29
这里是 30
这里是 31
这里是 32
这里是 33
这里是 34
这里是 35
这里是 36
这里是 37
这里是 38
这里是 39
这里是 40
这里是 41
这里是 42
这里是 43
这里是 44
这里是 45
这里是 46
这里是 47
这里是 48
这里是 49
这里是 50
这里是 51
这里是 52
这里是 53
这里是 54
这里是 55
这里是 56
这里是 57
这里是 58
这里是 59
这里是 60
这里是 61
这里是 62
这里是 63
这里是 64
这里是 65
这里是 66
66
49
11
49
49
49
12
51
58
58
58
58
这里是 67
这里是 68
这里是 69
这里是 70
这里是 71
这里是 72
这里是 73
这里是 74
这里是 75
这里是 76
这里是 77
这里是 78
这里是 79
这里是 80
这里是 81
这里是 82
这里是 83
这里是 84
67
67
49
67
7
67
49
67
9
67
49
67
7
67
49
67
7
67
49
67
9
67
49
67
7
67
49
67
10
67
49
67
7
67
67
67
67
67
68
67
67
69
67
70
67
71
72
67
67
73
67
74
67
75
67
76
67
77
67
78
67
79
67
80
67
81
67
82
7
83
这里是 85
85
85
7
这里是 86
这里是 87
这里是 88

goroutine中的i变量是闭包中的一个变量,它引用的是循环变量i的当前值。由于goroutine是并发执行的,它们可能不会按照创建它们的顺序执行。因此,当goroutine执行时,循环可能已经完成了多次迭代,i的值可能已经不是goroutine启动时的值了。


在这段代码中,所有的goroutine都会打印同一个值,即循环结束时i的值,也就是100。这是因为在goroutine被调度执行时,它们捕获的是循环变量i的最终值。


为了在goroutine中正确打印每次迭代的i值,你需要确保每个goroutine捕获的是迭代时的i值的一个副本。这可以通过传递i给匿名函数来实现:


go
func main() {
	for i := 0; i < 100; i++ {
		go func(i int) {
			fmt.Println(i)
		}(i) // 将当前的i值作为参数传递给匿名函数
	}

	fmt.Println("main")
	time.Sleep(10 * time.Second) // 等待所有goroutine执行完成
}

在这个修改后的代码中,每次迭代都会创建一个新的i值的副本,并将其传递给匿名函数。这样,每个goroutine都会打印出它被创建时的i值。由于goroutine的调度和执行可能仍然不是顺序的,所以打印的顺序可能仍然是随机的,但至少每个goroutine打印的值将是正确的。