多go程通信(管道channel)

go 程通信

1、当涉及到多go程时,c 是使用互斥量,上锁来保持资源同步,避免资源竞争问题
2、go语言也支持这种方式,但go语言更好的解决方案是使用管道、通道channel
3、使用通道不需要我们去加锁
4、A往通道里写数据, B从通道中读数据,go自动帮我们做好了数据同步

用例:

package main

import (
	"fmt"
)

func main() {
	// 创建管道
	// 无缓冲通道
	numChan := make(chan int) // 装数字的管道, 使用管道时一定要用make,同map一样,否则是nil	
	// strChan := make(chan string) // 装字符串的管道

	// 有缓冲通道
	// numChan := make(chan int, 10)

go func() { for i := 0; i < 50; i++ { // 从管道中读出数据 res := <-numChan fmt.Printf("**** 读出 i: %v ****\n", res) } }() go func() { for i := 0; i < 20; i++ { // 向管道中写入数据 numChan <- i fmt.Printf("==子go程===>写入i: %d\n", i) // time.Sleep(1 * time.Second) } }() for i := 20; i < 50; i++ { // 向管道中写入数据 numChan <- i fmt.Printf("==主go程===>写入i: %d\n", i) // time.Sleep(1 * time.Second) } }

结论

1、当缓冲写满的时候,写阻塞;被读取后,再次恢复写。
2、当缓冲区读取完毕,读阻塞。
3、如果管道没有使用make分配空间,那么管道默认是nil的, 读取、写入都会阻塞。
4、对于一个管道,读与写的次数,必须对等。

 

通道读写对等

go通道使用时,要求我们读写一致,如果不一致会导致一下情况:

1、当读程序是在主进程进行时, 那么会导致程序崩溃

2、当读程序是在go程进行时, 那么会导致内存泄漏。(此时程序不会崩溃,但是会导致资源无法释放)

用例:

package main

import (
	"fmt"
	"time"
)

func main() {

	// 有缓冲管道
	nummChan := make(chan int, 10)

	// 写
	go func() {
		for i := 0; i < 20; i++ {
			nummChan <- i
			fmt.Printf("子go程写: %v\n", i)
		}
	}()

	// 读:go程
	go func() {
		for i := 0; i < 30; i++ {
			aa := <-nummChan
			fmt.Printf("主进程读: %v\n", aa)
		}
	}()

	// 读:主进程
	// for i:=0; i<30;i++ {
	// 	aa := <- nummChan
	// 	fmt.Printf("主进程读: %v\n", aa)
	// }

	for {
		fmt.Printf("----> 主进程, 死循环\n")
		time.Sleep(1 * time.Second)
	}

}
  • 当执行主进程读时, 程序读取超出后会立即崩溃
  • 当执行go程读时, 程序读取超出后会阻塞住(结论2

 

for - range 变量管道

1、遍历管道时,只返回一个值

2、for range 是不知道管道是否已经写完,所以会一直在这里等待

3、在写入端,将管道关闭,for range 关闭的管道时,会自动退出

用例:

package main

import (
	"fmt"
)


func main() {
numChan := make(chan int, 10) // 写 go func () { for i:=0; i<20; i++ { numChan <- i fmt.Printf("----> 子go程写入数据\n") } fmt.Printf("===== 写入完毕 =====") close(numChan) }() // 读 for i:= range numChan { fmt.Printf("--> 主进程读: %v\n", i) } }

  

总结:

  1. 当管道写满了,写阻塞。
  2. 当缓冲读完了,读阻塞。
  3. 如果管道没有使用make分配空间,管道默认是nil 值
  4. 从nil 的管道中读取数据、写入数据,都是阻塞(注意:不会崩溃)
  5. 从一个close的管道中读取数据,会返回零值(不会崩溃)
  6. 关闭一个已经close的管道,程序会崩溃
  7. 关闭管道的操作应该放在写入端
  8. 读、写次数一定要对等,否则:
    1. 在多个go程中,资源泄露
    2. 在主go程中,程序崩溃(报:deadlock!)

 

posted @ 2022-09-15 11:26  萤huo虫  阅读(140)  评论(0编辑  收藏  举报