GO語言學習——(2) channel實操之通道阻塞

   先初始化一個通道,最大容量是三個元素,當向該通道發送三個值後,該通道已滿,再向其發送數據,將會被阻塞。當然,此時你可以從通道中拿出一個數據,那之前的發送數據的goroutine會被喚醒。看一下下面的程序:

// 85_chanbase1
package main

import (
	"fmt"
	"time"
)

var strChan = make(chan string, 3)

func main() {
	synChan1 := make(chan struct{}, 1)
	synChan2 := make(chan struct{}, 2)
	go func() { // 用於演示接收操作
		<-synChan1
		fmt.Println("Received a sync signal and wait a second ... [receiver]")
		time.Sleep(time.Second)
		for {
			if elem, ok := <-strChan; ok {
				fmt.Println("Received: ", elem, "[receiver]")
			} else {
				break
			}
		}
		fmt.Println("Stopped. [receiver]")
		synChan2 <- struct{}{}
	}()
	go func() { //用於演示發送操作
		for _, elem := range []string{"a", "b", "c", "d"} {
			strChan <- elem
			fmt.Println("Sent: ", elem, "[sender]")
			if elem == "c" {
				synChan1 <- struct{}{}
				fmt.Println("Sent a sync signal. [sender]")
			}
		}
		fmt.Println("Wait 2 second...[sender]")
		time.Sleep(time.Second * 2)
		close(strChan)
		synChan2 <- struct{}{}
	}()

	<-synChan2
	<-synChan2

	fmt.Println("Hello World!")
}

運行結果:

Sent:  a [sender]
Sent:  b [sender]
Sent:  c [sender]
Sent a sync signal. [sender]
Received a sync signal and wait a second ... [receiver]
Sent:  d [sender]
Wait 2 second...[sender]
Received:  a [receiver]
Received:  b [receiver]
Received:  c [receiver]
Received:  d [receiver]
Stopped. [receiver]
Hello World!

     其中,syncChan2,這個通道純粹是爲了不讓主goroutine過早結束運行,一旦主goroutine運行結束,go程序的運行也就結束了。在main函數的最後試圖從synChan2接收值兩次,在這兩次接收都成功完成之前,主goroutine會阻塞於此。把syncChan的容量設定爲2,這是因爲main函數中起用了兩個goroutine,這樣一來他們可以不受干擾的向synChan2發送值。一旦那兩個goroutine都向syncChan2發送了值,主goroutine就會恢復運行,但隨後又會結束運行。

    注意,程序中的struct{}成爲空結構體類型,在go語言中,空結構體類型的變量是不會佔用內存的,並且所有該類型的變量都擁有相同的內存地址。建議用於傳遞“信號”的通道都可以以struct{}作爲元素類型,除非需要傳遞更多的信息。 

   注意點:

  1、試圖向一個已關閉的通道發送元素值,會立即引發一個運行時恐慌

  2、如果有多個goroutine因像一個已滿的通道發送元素值而被阻塞,那麼而當該通道有多餘空間時,最早被阻塞的那個goroutine會最先被喚醒。對於接收操作也是如此。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章