Go中并发编程 | 青训营笔记

54 阅读2分钟

并发编程

并发 多线程程序在一个核的CPU上运行 并行 多线程程序在多个核的CPU上运行

Go有高效的调度模型, 可以充分发挥多核优势, 高效运行

Goroutine

协程: 用户态, 轻量级线程, 栈KB级别 线程: 内核态, 线程跑多个协程, 栈MB级别

package main

import (
	"strconv"
	"time"
)

func main() {
	for i := 0; i < 5; i++ {
		go func(i int) {
			println("hello goroutine: " + strconv.Itoa(i))
		}(i)
	}
	time.Sleep(time.Second)
}

CSP(Communicating Sequential Processes)

Pasted image 20230513153702.png 提倡通过通信共享内存而不是通过共享内存而实现通信

Channel

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

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

Pasted image 20230513153937.png eg: A协程发送数字 0 ~ 9, B协程计算数字的平方, 主协程输出计算结果 带缓冲的channel可以缓解生产者消费者速度不匹配的问题

package main

import (
	"fmt"
	"time"
)

func main() {
	src := make(chan int)
	desc := make(chan int)

	go func() {
		defer close(src)
		// 生产
		for i := 0; i < 10; i++ {
			src <- i
			time.Sleep(500 * time.Millisecond)
		}
	}()

	go func() {
		defer close(desc)
		// 消费并生产
		for v := range src {
			desc <- v * v
		}
	}()

	// 消费
	for v := range desc {
		fmt.Println(v)
	}
}

并发安全 Lock

package main

import (
	"fmt"
	"sync"
	"time"
)

var x int64
var lock sync.Mutex

func addWithLock() {
	for i := 0; i < 100000; i++ {
		lock.Lock()
		x += 1
		lock.Unlock()
	}
}

func addWithoutLock() {
	for i := 0; i < 100000; i++ {
		x += 1
	}
}

func main() {
	x = 0
	for i := 0; i < 5; i++ {
		go addWithoutLock()
	}
	time.Sleep(time.Second)
	fmt.Println(x)
	x = 0
	for i := 0; i < 5; i++ {
		go addWithLock()
	}
	time.Sleep(time.Second)
	fmt.Println(x)
}

WaitGroup

通过sleep强制阻塞固定时间, 不够优雅, 可以使用WaitGroup实现同步

package main

import (
	"fmt"
	"sync"
)

var x int64
var lock sync.Mutex
var wg sync.WaitGroup

func addWithLock() {
	defer wg.Done()
	for i := 0; i < 100000; i++ {
		lock.Lock()
		x += 1
		lock.Unlock()
	}
}

func addWithoutLock() {
	defer wg.Done()
	for i := 0; i < 100000; i++ {
		x += 1
	}
}

func main() {
	wg.Add(5)
	x = 0
	for i := 0; i < 5; i++ {
		go addWithoutLock()
	}
	wg.Wait()
	fmt.Println(x)
	wg.Add(5)
	x = 0
	for i := 0; i < 5; i++ {
		go addWithLock()
	}
	wg.Wait()
	fmt.Println(x)
}