Go语言进阶 | 青训营笔记

47 阅读1分钟

4. Go进阶

4.1 Goroutine

线程与协程

协程:用户态轻量级线程,kb级别 线程:内核态线程跑多个协程,mb级别

image-routine.png

func hello(i int) {
	println("hello goroutine:" + fmt.Sprint(i))
}

func main() {
	for i := 0; i < 5; i++ {
		go func(j int) {
			hello(j)
		}(i)
	}
	time.Sleep(time.Second)
}

hello goroutine:1 hello goroutine:2 hello goroutine:3 hello goroutine:0 hello goroutine:4

4.2 CSP

go提倡通过通信共享内存而不是通过共享内存进行通信

image-csp.png

4.3 Channel

make(chan 元素类型,[缓冲大小])

  • 无缓冲通道 make(chan int)
  • 有缓冲通道 make(chan int, 2)

image-channel.png

  1. 子协程发送0~9数字
  2. 子协程计算输入数字的平方
  3. 主协程输出最后平方数
package main

func main() {
	src := make(chan int)
	dest := make(chan int, 3)
	go func() {
        // 生产
		defer close(src)
		for i := 0; i < 10; i++ {
			src <- i
		}
	}()
	go func() {
        // 消费
		defer close(dest)
		for i := range src {
			dest <- i * i
		}
	}()
	for i := range dest {
		// 复杂操作
		println(i)
	}
}

4.4 并发安全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 main() {
	x = 0
	for i := 0; i < 5; i++ {
		go addWithoutLock()
	}
	time.Sleep(time.Second)
	println("WithoutLock:", x)
	x = 0
	for i := 0; i < 5; i++ {
		go addWithLock()
	}
	time.Sleep(time.Second)
	println("WithLock:", x)
}

LockResult.png

4.5 WaitGroup

image-waitgroup.png

计数器

开启协程+1;执行结束-1;主协程阻塞到计数器为0

快速打印hello goroutine:0~4

旧[不安全]

func hello(i int) {
	println("hello goroutine: " + fmt.Sprint(i))
}

func main() {
	for i := 0; i < 5; i++ {
		go func(j int) {
			hello(j)
		}(i)
	}
	time.Sleep(time.Second)
}

waitgroupresult.png

新[安全]

func hello(i int) {
	println("hello goroutine: " + fmt.Sprint(i))
}

func main() {
	var wg sync.WaitGroup
	// 计数器+delta
	wg.Add(5)
	for i := 0; i < 5; i++ {
		go func(j int) {
			// 计数器-1
			defer wg.Done()
			hello(j)
		}(i)
	}
	// 主协程阻塞 计数器为0->推出主协程
	wg.Wait()
}

waitgroupresult2.png