Groutine
协程:用户态,轻量级线程,栈KB级别
线程:内核态,线程跑多个协程,栈MB级别
func hello(i int) {
println("hello goroutine : " + fmt.Sprint(i))
}
func HelloGoRoutine() {
for i := 0; i < 5; i++ {
go func(j int) {
hello(j)
}(i)
}
time.Sleep(time.Second)
}
func hello(i int) {
println("hello goroutine : " + fmt.Sprint(i))
}
func HelloGoRoutine() {
for i := 0; i < 5; i++ {
go hello(i)
}
time.Sleep(time.Second)
}
以上两个代码等效
CSP(communicating sequential processes)
Channel
make(chan type, [size])
// 无缓冲通道 make(chan int)
// 有缓冲通道 make(chan int, 2)
func CalSquare() {
src := make(chan int) // 创建一个无缓冲的整数类型通道 src
dest := make(chan int, 3) // 创建一个缓冲为 3 的整数类型通道 dest
go func() { // 启动一个匿名的 goroutine
defer close(src) // 在 goroutine 结束时关闭 src 通道
for i := 0; i < 10; i++ { // 迭代 0 到 9
fmt.Printf("i : %v \n", i) // 打印当前迭代值 i
time.Sleep(time.Second) // 休眠一秒钟
src <- i // 将当前迭代值发送到 src 通道
}
}()
go func() { // 启动另一个匿名的 goroutine
defer close(dest) // 在 goroutine 结束时关闭 dest 通道
for i := range src { // 从 src 通道接收值,直到通道关闭
fmt.Printf("i*i : %v \n", i*i) // 打印接收到的值的平方
time.Sleep(time.Second) // 休眠一秒钟
dest <- i * i // 将接收到的值的平方发送到 dest 通道
}
}()
for i := range dest { // 从 dest 通道接收值,直到通道关闭
println(i) // 打印接收到的值
}
}
通过使用 Goroutine,这段代码实现了并发的数据流动。第一个 Goroutine 从 0 到 9 迭代并发送值到 src 通道,第二个 Goroutine 从 src 通道接收值并计算平方后发送到 dest 通道。主函数中的 for range dest 则从 dest 通道接收值并打印。这样,整个过程可以并发地执行,提高了程序的效率和响应能力。
在这段代码中,当协程执行 **defer close(src)** 的时候,**for i := range src** 才会退出循环
并发安全 Lock
var (
x int64
lock sync.Mutex
)
func addWithLock() {
for i := 0; i < 2000; i++ {
lock.Lock()
x += 1
lock.Unlock()
}
}
func addWithoutLock() {
for i := 0; i < 2000; i++ {
x += 1
}
}
func Add() {
x = 0
for i := 0; i < 5; i++ {
go addWithoutLock()
}
time.Sleep(time.Second)
fmt.Println("WithoutLock:", x)
x = 0
for i := 0; i < 5; i++ {
go addWithLock()
}
time.Sleep(time.Second)
println("WithLock:", x)
}
WithoutLock: 6574
WithLock: 10000
WaitGroup
sync.WaitGroup 是 Go 语言标准库中提供的一种机制,用于等待一组 Goroutine 完成其任务。
func hello(i int) {
println("hello goroutine : " + fmt.Sprint(i))
}
func HelloGoRoutine() {
var wg sync.WaitGroup // 创建一个 WaitGroup 对象
wg.Add(5) // 增加 WaitGroup 的计数器为 5
for i := 0; i < 5; i++ {
go func(j int) {
defer wg.Done() // 当 Goroutine 完成任务时,调用 wg.Done() 减少计数器的值
hello(j)
}(i)
}
wg.Wait() // 等待 WaitGroup 的计数器减少为 0,即所有 Goroutine 完成任务
}
- 首先创建了一个
sync.WaitGroup对象wg。然后,通过wg.Add(5)将计数器的值增加为 5,表示有 5 个 Goroutine 需要完成任务。 - 在每个 Goroutine 内部,通过
defer wg.Done()来减少WaitGroup的计数器值。 - 在
wg.Wait()语句处等待WaitGroup的计数器值减少为 0。这将阻塞主 Goroutine,直到所有的 Goroutine 完成任务并调用wg.Done(),计数器的值减少为 0。然后程序继续执行。