channel的基本使用


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

其他關於通道的使用可以看這兩篇博客
go通道的常見使用場景.
go通道的優雅關閉.



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM