欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

channel的基本使用

程序员文章站 2022-03-25 17:19:08
1、管道分类 读写管道 只读管道 只写管道 缓冲通道 :创建时指定大小(如果不指定默认为非缓冲通道) 2、正确使用管道 1. 管道关闭后自能读,不能写 2. 写入管道不能超过管道的容量 cap ,满容量还写则会阻塞 3. 管道为空时,如果没有关闭,则继续读取会阻塞当前线程,直到有东西写入管道 4. ......

1、管道分类

  • 读写管道
  • 只读管道
  • 只写管道
  • 缓冲通道 :创建时指定大小(如果不指定默认为非缓冲通道)

2、正确使用管道

  1. 管道关闭后自能读,不能写

  2. 写入管道不能超过管道的容量cap,满容量还写则会阻塞

  3. 管道为空时,如果没有关闭,则继续读取会阻塞当前线程,直到有东西写入管道

  4. m,ok:=<-intchan  //ok用来检测产是否已经关闭 false代表关闭了,关闭了m就是默认值
    

    一般如下操作才可以判断读取是否完毕,如果写进程没有关闭管道则说明还有东西要写

    v,ok:=<-intchan
    if !ok{
    	fmt.println("读取完毕")
    	break
    }
    

3、管道遍历与访问

  • for-range访问
  • select访问(常用)

for-range

//gor-range  如果管道没有数据同时还没有关闭  则会一直阻塞等待
	go func() {
		for i:=range c{ //注意这里没有ok判断是否关闭了 只有一个返回值
			fmt.println(i)
		}
	}()

下面这种情况for-range会阻塞,1秒后打印1,和 “关闭了”,如果没写同时又没有关闭,那么则会一直阻塞

	ch := make(chan int)	
	go func() {
		time.sleep(time.second)
		//close(ch)
		ch<-1
	}()
	go func() {
	for i:=range ch{
		log.println(i)
	}
   log.println("关闭了")
	}()
	time.sleep(time.hour)

下面的这种情况,for-range在一秒后会结束 ,同时打印“关闭了

	ch := make(chan int)	
	go func() {
		time.sleep(time.second)
		close(ch)
		//ch<-1
	}()
	go func() {
		for i:=range ch{
			log.println(i)
		}
		log.println("关闭了")
	}()
	time.sleep(time.hour)

select

select会随机选择case里面没有阻塞的管道进行读取或写入,如果都阻塞则执行default语句,一般select都会伴随一个default语句

	c:=make(chan string,2)
	send:= func(v string) {
		select {
		case c<-v:log.println("输入",v)
		default:log.println("缓冲区已经满")
		}
	}

	receive:= func() string {
		select {
		case v:=<-c:return v
		default:
			log.println("缓冲区空")
			return ""
		}
	}


	send("h1")
	send("h2")
	send("h3") //输入失败

	log.println(receive())
	log.println(receive())
	log.println(receive()) //取失败

当管道关闭时,select也会执行成功,如下打印了一秒‘等' 之后就会结束,这里没有往管道写东西,所以结束时打印的是默认值0

	ch := make(chan int)
	//go func() {
	//	ch <- 1
	//}()
	go func() {
		time.sleep(time.second)
		close(ch)
		
	}()
	go func() {
		for {
			time.sleep(time.microsecond*500)
			select {
			case v := <-ch:
				log.println(v)
				return
			default:
				log.println("等")
			}
		}
	}()
	time.sleep(time.hour)

4、阻塞情况

1、没有关闭,同时管道元素为0,读进程阻塞

2、没有关闭,同时管道元素已经满,则写进程阻塞,无缓冲管道的话则会阻塞在写,直到有人读

3、关闭管道,读光了还读,则读取出来的是对应类型管道的默认空值,在一个关闭通道进行写操作会报错

	ch:=make(chan int,1)
	ch<-1
	close(ch)

	log.println(<-ch) //1
	log.println(<-ch) //0
	log.println(<-ch)//0
	a,ok:=<-ch
	log.println(a,ok)//0 false
  1. 关闭管道,还写,则报错

  2. 无缓冲=堵塞,缓冲=非堵塞 无缓冲是同步,有缓冲是异步

像下面这个无缓冲管道,没人读则一直阻塞,只会打印a1,有一个管道读走了才会继续执行写操作,就比如快递员来发快递,只会等你拿走快递才会离开,否则一直在等你来拿

	ch := make(chan int)
	go func() {
		for{
			log.println("a1")
			time.sleep(time.second)
			//close(ch)
			ch<-1
			log.println("a2")
		}

	}()

那如果我把cap设置成1呢?

	ch := make(chan int,1)
	go func() {
		for{
			log.println("a1")
			time.sleep(time.second)
			//close(ch)
			ch<-1
			log.println("a2")
		}

	}()

打印如下,可以写一个

2020/03/21 20:02:59 a1
2020/03/21 20:03:00 a2
2020/03/21 20:03:00 a1