什么时候用Goroutine?什么时候用Channel?
Golang
421
0
0
2022-11-27
什么场景下用channel合适呢?
- 通过全局变量加锁同步来实现通讯,并不利于多个协程对全局变量的读写操作。
- 加锁虽然可以解决goroutine对全局变量的抢占资源问题,但是影响性能,违背了原则。
- 总结:为了解决上述的问题,我们可以引入channel,使用channel进行协程goroutine间的通信。
Go语言中的操作系统线程和goroutine的关系:
- 一个操作系统线程对应用户态多个goroutine。
- go程序可以同时使用多个操作系统线程。
- goroutine和OS线程是多对多的关系,即m:n。
Go语言的并发模型是CSP(Communicating Sequential Processes),提倡通过通信共享内存而不是通过共享内存而实现通信,引出了channel。
通道channel使用示例:
for range 从通道中取值,通道关闭时for range 退出
| |
| ch1 := make(chan int) |
| ch2 := make(chan int) |
| |
| |
| go func() { |
| for i := 0; i < 100; i++ { |
| ch1 <- i |
| } |
| close(ch1) |
| }() |
| |
| |
| go func() { |
| for { |
| i,ok := <-ch1 |
| if ok { |
| ch2 <- i*i |
| }else { |
| break |
| } |
| } |
| close(ch2) |
| }() |
| |
| |
| |
| for i :=range ch2{ |
| fmt.Println(i) |
| } |
channel升级,单通道,只读通道和只写通道
| func counter(in chan<- int) { |
| defer close(in) |
| for i := 0; i < 100; i++ { |
| in <- i |
| } |
| } |
| |
| func square(in chan<- int, out <-chan int) { |
| defer close(in) |
| for i := range out { |
| in <- i * i |
| } |
| } |
| |
| func output(out <-chan int) { |
| for i:=range out{ |
| fmt.Println(i) |
| } |
| } |
| |
| |
| func main() { |
| ch1 := make(chan int) |
| ch2 := make(chan int) |
| go counter(ch1) |
| go square(ch2, ch1) |
| output(ch2) |
| } |
goroutine work pool,可以防止goroutine暴涨或者泄露
| |
| func worker(id int, jobs <-chan int, results chan<- int) { |
| for j := range jobs { |
| fmt.Printf("worker:%d start job:%d\n", id, j) |
| time.Sleep(time.Second) |
| fmt.Printf("worker:%d end job:%d\n", id, j) |
| results <- j * 2 |
| } |
| } |
| |
| func main() { |
| jobs := make(chan int, 100) |
| results := make(chan int, 100) |
| |
| for w := 1; w <= 3; w++ { |
| go worker(w, jobs, results) |
| } |
| |
| for j := 1; j <= 5; j++ { |
| jobs <- j |
| } |
| close(jobs) |
| |
| for a := 1; a <= 5; a++ { |
| <-results |
| } |
| } |
goroutine使用select case多路复用,满足我们同时从多个通道接收值的需求
| |
| |
| |
| |
| ch := make(chan int, 1) |
| go func() { |
| for i := 0; i < 10; i++ { |
| select { |
| case x := <-ch: |
| fmt.Println(x) |
| case ch <- i: |
| } |
| } |
| }() |
goroutine加锁 排它锁 读写锁
| var x int64 |
| var wg sync.WaitGroup |
| |
| var lock sync.Mutex |
| |
| func main() { |
| wg.Add(2) |
| go add() |
| go add() |
| wg.Wait() |
| fmt.Println(x) |
| } |
| |
| func add() { |
| for i := 0; i < 5000; i++ { |
| lock.Lock() |
| x = x + 1 |
| lock.Unlock() |
| } |
| wg.Done() |
| } |