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会最先被唤醒。对于接收操作也是如此。

猜你喜欢

转载自blog.csdn.net/u013276277/article/details/90373602
今日推荐